Qt多线程之死锁

tech2022-10-05  130

目录

一、造成死锁的原因

现象分析

二、死锁的概念和发生条件

三、死锁的避免

四、避免死锁的示例代码


一、造成死锁的原因

一般性原则,每个临界资源都需要一个线程锁来进行保护,假设有多个线程锁该怎么设计程序呢?先来看以下的一个示例(代码很简单就不加注释了):

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QDebug> int g_i_current_data = 0; QMutex g_mutex_1; QMutex g_mutex_2; class ThreadMutexA : public QThread { protected: void run() { qDebug() << objectName() << ": run begin..."; while( true ) { g_mutex_1.lock(); qDebug() << objectName() << "get mutex_1..."; g_mutex_2.lock(); qDebug() << objectName() << "get mutex_2..."; g_i_current_data++; qDebug() << objectName() << ": " << g_i_current_data; g_mutex_2.unlock(); g_mutex_1.unlock(); msleep(1); } qDebug() << objectName() << ": run end..."; } }; class ThreadMutexB : public QThread { protected: void run() { qDebug() << objectName() << ": run begin..."; while( true ) { g_mutex_2.lock(); qDebug() << objectName() << "get mutex_2..."; g_mutex_1.lock(); qDebug() << objectName() << "get mutex_1..."; g_i_current_data--; qDebug() << objectName() << ": " << g_i_current_data; g_mutex_1.unlock(); g_mutex_2.unlock(); msleep(1); } qDebug() << objectName() << ": run end..."; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main begin..."; ThreadMutexA thread_a; ThreadMutexA thread_a1; ThreadMutexA thread_a2; ThreadMutexB thread_b; ThreadMutexB thread_b1; thread_a.setObjectName("ThreadMutexA"); thread_a1.setObjectName("ThreadMutexA_1"); thread_a2.setObjectName("ThreadMutexA_2"); thread_b.setObjectName("ThreadMutexB"); thread_b1.setObjectName("ThreadMutexB_1"); thread_a.start(); thread_a1.start(); thread_a2.start(); thread_b.start(); thread_b1.start(); qDebug() << "main end..."; return a.exec(); }

现象分析

1、现象:五个线程分别都进入了run()函数中,线程锁1和线程锁2分别被线程A和线程B获取(这两个线程动作比较快优先获取到线程数)后,程序就阻塞在这里了,不继续往下执行了。

2、分析:

(1)当线程A获取线程锁1时,就要继续获取线程锁2,但是此时线程锁2被线程B获取,线程A就只好等待线程锁2被释放;

(2)线程B获取线程锁2后,需要继续获取线程锁1,而此时线程锁1被线程A锁获取并没有释放,线程B也就只好等待线程A释放线程锁1了;

(3)两个线程一直等待彼此释放相应线程锁,等到花都谢了也等不到,程序无法继续执行。

3、原因:造成了线程的死锁

二、死锁的概念和发生条件

1、死锁概念:多线程之间相互等待临界资源而造成彼此无法继续执行。

2、死锁发生条件:(1)系统中存在多个临界资源且临界资源不可抢占;(2)每个线程需要多个临界资源才能继续执行。

三、死锁的避免

1、对所有临界资源都分配唯一的序号(R1, R2, R3, ..., Rn);

2、对应的线程锁也分配同样的序号(M1, M2, M3, ..., Mn);

3、系统中的每个线程必须按照严格的升序的次序去请求资源。

ThreadMutexA A; mutex_1.lock(); mutex_2.lock(); mutex_3.lock(); mutex_4.lock();

四、避免死锁的示例代码

#include <QCoreApplication> #include <QThread> #include <QMutex> #include <QDebug> int g_i_current_data = 0; QMutex g_mutex_1; QMutex g_mutex_2; class ThreadMutexA : public QThread { protected: void run() { qDebug() << objectName() << ": run begin..."; while( true ) { g_mutex_1.lock(); qDebug() << objectName() << "get mutex_1..."; g_mutex_2.lock(); qDebug() << objectName() << "get mutex_2..."; g_i_current_data++; qDebug() << objectName() << ": " << g_i_current_data; g_mutex_2.unlock(); g_mutex_1.unlock(); msleep(1); } qDebug() << objectName() << ": run end..."; } }; class ThreadMutexB : public QThread { protected: void run() { qDebug() << objectName() << ": run begin..."; while( true ) { g_mutex_1.lock(); qDebug() << objectName() << "get mutex_1..."; g_mutex_2.lock(); qDebug() << objectName() << "get mutex_2..."; g_i_current_data--; qDebug() << objectName() << ": " << g_i_current_data; g_mutex_1.unlock(); g_mutex_2.unlock(); msleep(1); } qDebug() << objectName() << ": run end..."; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug() << "main begin..."; ThreadMutexA thread_a; ThreadMutexA thread_a1; ThreadMutexA thread_a2; ThreadMutexB thread_b; ThreadMutexB thread_b1; thread_a.setObjectName("ThreadMutexA"); thread_a1.setObjectName("ThreadMutexA_1"); thread_a2.setObjectName("ThreadMutexA_2"); thread_b.setObjectName("ThreadMutexB"); thread_b1.setObjectName("ThreadMutexB_1"); thread_a.start(); thread_a1.start(); thread_a2.start(); thread_b.start(); thread_b1.start(); qDebug() << "main end..."; return a.exec(); }

最新回复(0)