线程的死锁概念
-线程间相互等待临界资源而造成批次无法继续执行
发生死锁的条件
-系统中存在多个临界资源且临界资源不可抢占
-线程需要多个临界资源才能继续执行
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QMutex>
QMutex g_mutex_1;
QMutex g_mutex_2;
class ThreadA : public QThread
{
protected:
void run()
{
while(true)
{
g_mutex_1.lock();
qDebug() << objectName() << "get m1";
g_mutex_2.lock();
qDebug() << objectName() << "get m2";
qDebug() << objectName() << "do work ...";
g_mutex_1.unlock();
g_mutex_2.unlock();
}
}
};
class ThreadB : public QThread
{
protected:
void run()
{
while(true)
{
g_mutex_2.lock();
qDebug() << objectName() << "get m2";
g_mutex_1.lock();
qDebug() << objectName() << "get m1";
qDebug() << objectName() << "do work ...";
g_mutex_2.unlock();
g_mutex_1.unlock();
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication _a(argc, argv);
ThreadA a;
ThreadB b;
a.setObjectName("a");
b.setObjectName("b");
a.start();
b.start();
return _a.exec();
}
死锁的避免
-对所有的临界资源都分配一个唯一的序号(r1,r2,r3.......rn)
-对应的线程锁也分配同样的序号(m1,m2,m3.......mn)
-系统中的每个线程按照严格递增的次序请求资源
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QMutex>
QMutex g_mutex_1;
QMutex g_mutex_2;
class ThreadA : public QThread
{
protected:
void run()
{
while(true)
{
g_mutex_1.lock();
qDebug() << objectName() << "get m1";
g_mutex_2.lock();
qDebug() << objectName() << "get m2";
qDebug() << objectName() << "do work ...";
g_mutex_1.unlock();
g_mutex_2.unlock();
}
}
};
class ThreadB : public QThread
{
protected:
void run()
{
while(true)
{
g_mutex_1.lock();
qDebug() << objectName() << "get m2";
g_mutex_2.lock();
qDebug() << objectName() << "get m1";
qDebug() << objectName() << "do work ...";
g_mutex_1.unlock();
g_mutex_2.unlock();
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication _a(argc, argv);
ThreadA a;
ThreadB b;
a.setObjectName("a");
b.setObjectName("b");
a.start();
b.start();
return _a.exec();
}
信号量的概念
-信号量是特殊的线程锁
-信号量允许N个线程同时访问临界资源
-Qt中直接支持信号量(QSemaphore)
ps:QSemaphore对象中维护了一个整形值,acquire()是的该值减1,release()使得该值加1,当该值为0时,acquire()函数将阻塞当前线程
#include <QCoreApplication>
#include <QThread>
#include <QSemaphore>
#include <QDebug>
const int SIZE = 5;
unsigned char g_buff[SIZE] = {0};
QSemaphore g_sem_free(SIZE);
QSemaphore g_sem_used(0);
class Producer : public QThread
{
protected:
void run()
{
while(true)
{
int value = qrand() % 256;
g_sem_free.acquire();
for(int i = 0; i<SIZE;i++)
{
if(!g_buff[i])
{
g_buff[i] = value;
qDebug() << objectName() << " generate: (" << i << ", "<<value << ")";
break;
}
}
g_sem_used.release();
}
}
};
class Customer : public QThread
{
protected:
void run()
{
while(true)
{
g_sem_used.acquire();
for(int i = 0; i<SIZE;i++)
{
if(g_buff[i])
{
int value = g_buff[i];
g_buff[i] = 0;
qDebug() << objectName() << "consume: (" << i << "," << value << ")";
break;
}
}
g_sem_free.release();
sleep(2);
}
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Producer p1;
Producer p2;
Producer p3;
p1.setObjectName("p1");
p1.setObjectName("p2");
p1.setObjectName("p3");
Customer c1;
Customer c2;
c1.setObjectName("c1");
c2.setObjectName("c2");
p1.start();
p2.start();
p3.start();
c1.start();
c2.start();
return a.exec();
}
总结:
-多线程间相互等待临界资源将导致死锁
-可以对临界资源进行编号的方法发避免死锁
-所有线程必须按照严格递增的次序请求资源
-Qt中直接支持信号量(QSemaphore)
-信号量允许N个线程同时访问临界资源