问题:程序有多少临界资源?需要多少线程锁?
临界资源是没有任何的限制
一般性原则:每一个临界资源都需要一个线程锁进行保护(一 一对应)
定义了两把线程锁,显然是为了保护两个临界资源而定义的。在线程A中需要两个临界资源才能保证工作,这两个临界资源对应的线程锁就是m1,m2。在线程B中也需要两个临界资源才能保证工作。单看线程A和线程B都是正确的,那么它们两个加在一起就是多线程程序吗?这是一个非常有趣的问题,有趣的地方在于它们获取线程锁的顺序是不一样的。接下来就进行研究
有趣的示例:
#include <QCoreApplication> #include <QThread> #include <QDebug> #include <QMutex> QMutex q_mutex_1; QMutex q_mutex_2; class ThreadA : public QThread { protected: void run() { while(true) { q_mutex_1.lock(); qDebug() << objectName() << "get m1"; q_mutex_2.lock(); qDebug() << objectName() << "get m2"; qDebug() << objectName() << "do work...."; q_mutex_2.unlock(); q_mutex_1.unlock(); } } }; class ThreadB : public QThread { protected: void run() { while(true) { q_mutex_2.lock(); qDebug() << objectName() << "get m2"; q_mutex_1.lock(); qDebug() << objectName() << "get m1"; qDebug() << objectName() << "do work...."; q_mutex_1.unlock(); q_mutex_2.unlock(); } } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); ThreadA ta; ThreadB tb; ta.setObjectName("ta"); tb.setObjectName("tb"); ta.start(); tb.start(); return a.exec(); }
打印结果1:(注意这个地方的打印结果是不确定的)
上面已经分析过,线程A和线程B要想正确的执行,需要得到两把锁,m1和m2.。从打印结果看,线程A只得到了,锁m1,线程B得到了锁m2。当线程A在获得了锁m1后,再尝试获取第二把锁m2,但是此时锁m2被线程B得到了,线程A等待线程B释放m2,才能继续往下执行。然而,线程B等待线程A释放m1,才能继续向下运行。这两个线程都在互相等待,谁也不释放锁,这样就造成了无限的等待,造成了死锁。
线程A和线程B获取线程锁的顺序是不一样的。
线程的死锁概念
-线程间相互等待临界资源而造成彼此无法继续执行
发生死锁的条件:
-系统中存在多个临界资源且临界资源不可抢占
-线程需要多个临界资源才能继续执行
m1保护r1,m2保护r2,依次类推。
QMutex q_mutex_1; QMutex q_mutex_2; class ThreadA : public QThread { protected: void run() { while(true) { q_mutex_1.lock(); qDebug() << objectName() << "get m1"; q_mutex_2.lock(); qDebug() << objectName() << "get m2"; qDebug() << objectName() << "do work...."; q_mutex_2.unlock(); q_mutex_1.unlock(); sleep(1); } } }; class ThreadB : public QThread { protected: void run() { while(true) { q_mutex_1.lock(); qDebug() << objectName() << "get m1"; q_mutex_2.lock(); qDebug() << objectName() << "get m2"; qDebug() << objectName() << "do work...."; q_mutex_2.unlock(); q_mutex_1.unlock(); sleep(1); } } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); ThreadA ta; ThreadB tb; ta.setObjectName("ta"); tb.setObjectName("tb"); ta.start(); tb.start(); return a.exec(); }