一、多线程间的互斥
1、 生产消费者问题
1.1、 有n个生产者同时制造产品,并把产品放入仓库中
1.2、 有m个消费者同时从仓库中取出产品
1.3、 规则(产品是公共资源,同一时刻只能被一个线程访问)
A、 当仓库未满,任意生产者可以存入产品
B、 当仓库未空,任意消费者可以取出产品
2、 生活中的线程互斥例子
标示牌用于指示是否可用:
红绿灯标识十字路口是否可用:
3、 线程互斥的相关概念
3.1、 临界资源(Critical Resource):每次只允许一个线程访问(读/写)的资源
3.2、 线程间的互斥(竞争):多个线程在同一个时间都需要访问临界资源
3.3、 QMutex类是一把线程锁,保证线程间的互斥:利用线程锁能够保证临界资源的安全性
4、 QMutex中的关键成员函数(锁就是类似上面两个生活中例子的标识)
4.1、 void lock()
A、 当锁空闲时,获取锁并继续执行
B、 当锁被获取,堵塞并等待锁释放
4.2、 void unlock()
A、 释放锁(同一把锁的获取和释放必须在同一线程中成对出现,类似于new 和 delete)
用线程锁解决生产者消费者的问题
#include <QtCore/QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QMutex>
#include <QString>
#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);//移除第0个位置的一个字符
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("Producer");
c.setObjectName("Customer");
p.start();
c.start();
qDebug() << "main End";
return a.exec();
}
二、小结
1、 临界资源每次只允许一个线程访问(读/写)
2、 线程锁(QMutex)用于保护临界资源
3、 线程只有获取锁之后才能访问临界资源
4、 锁被其它线程获取时,当前线程处于等待状态
5、 线程锁的获取和释放必须在同一线程中成对出现(类似,new和delete)