一、多线程间的互斥
1、生产消费者问题
(1)、有n个生产者同时制造产品,并把产品放入仓库中
(2)、有m个消费者同时从仓库中取出产品
(3)、规则
A、当仓库未满,任意生产者可以存入产品
B、当仓库未空,任意消费者可以取出产品
2、生活中的线程互斥例子
标示牌用于指示是否可用:
红绿灯标识十字路口是否可用:
3、线程互斥的相关概念
(1)、临界资源(Critical Resource):每次只允许一个线程访问(读/写)的资源
(2)、线程间的互斥(竞争):多个线程在同一个时间都需要访问临界资源
(3)、QMutex类是一把线程锁,保证线程间的互斥:利用线程锁能够保证临界资源的安全性
4、QMutex中的关键成员函数(锁就是类似上面两个生活中例子的标识)
(1)、void lock()
A、当锁空闲时,获取锁并继续执行
B、当锁别人被获取,堵塞并等待锁释放
(2)、void unlock()
A、释放锁(同一把锁的获取和释放必须在同一线程中成对出现)
#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QDebug> #define MAXSTORAGE 10 //最大仓库容量 static QMutex g_mutex; static QString g_store; //生产者 class Producer : public QThread { protected: void run() { int count = 0; while(true)//保证每个一毫秒生产产品 { g_mutex.lock();//若没有锁,程序运行一下可能崩溃,因为两个线程是并行的,生产者写的时候消费者来读, //就会产生冲突 if(g_store.count() <= MAXSTORAGE) { g_store.append(QString::number((count++) % 10));//产生的数字总是在0-10之间 qDebug() << objectName() << ":" + g_store; } g_mutex.unlock(); msleep(1); } } }; //消费者 class Customer : public QThread { protected: void run() { while(true) { g_mutex.lock(); if(g_store.count()>0) { g_store.remove(0, 1); qDebug() << objectName() << ":" + g_store; } g_mutex.unlock(); msleep(1); } } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main begin"; Producer p; Customer c; p.setObjectName("Produer"); c.setObjectName("Customer"); p.start(); c.start(); qDebug() << "main end"; return a.exec(); }
二、小结
(1)、临界资源每次只允许一个线程访问(读/写)
(2)、线程锁(QMutex)用于保护临界资源
(3)、线程只有获取锁之后才能访问临界资源
(4)、锁被其它线程获取时,当前线程处于等待状态
(5)、线程锁的获取和释放必须在同一线程中成对出现