Qt中的线程同步
qt中实现了如下类,提供线程同步机制
- QMutex:互斥量。用来确保同一时刻,只能有一个线程访问某一资源。
- QReadWriteLock:读写锁。允许同一时刻多个线程读取某一资源,但只要有一个线程在写该资源,则不允许其他程同时读取该资源。
- QWaitCondition:等待条件。提供了一个条件变量同步线程,当某个条件满足时,可以发送信号通知其他线程该条件已经达到。
- QSemphone:信号量。能够保证同一时刻一个或多个资源不被并发访问,经常用在有限的相同资源条件下的线程同步。
线程同步之QMutex
Qt为我们提供了一系列的容器类,比如QList,QQueue,QStack等,但都是可重入(reentrant)而不是线程安全的(thread-safe)。因此当遇到多线程的容器共享时,我们就需要实现自己的线程安全版本容器,以QQueue为例:
// QSafeQueue.h
#include <QList>
#include <QMutex>
template<typename T>
class QSafeQueue
{
public:
QSafeQueue();
void push_back(const T& data);
T pop_front();
private:
QList<T> m_oList;
QMutex m_oMutex;
};
// QSafeQueue.cpp
template<typename T>
QSafeQueue<T>::QSafeQueue()
: m_oList(),
m_oMutex()
{
}
template<typename T>
void QSafeQueue<T>::push_back(const T &data)
{
m_oMutex.lock();
m_oList.push_back(data);
m_oMutex.unlock();
}
template<typename T>
T QSafeQueue<T>::pop_front()
{
if (m_oList.empty())
throw;
m_oMutex.lock();
T temp = m_oList.front();
m_oList.pop_front();
m_oMutex.unlock();
return temp;
}
针对上面的实现,考虑这样一种情况,假设队列很长,并且在某些时候从队列中读取数据的线程要远远多于向队列中添加数据,此时读线程的锁就会影响写线程,从而降低队列的执行效率,为此我们需要改进安全队列,使用读写两个不同的锁,看下列实现:
// QSafeQueue.h
#include <QList>
#include <QMutex>
template<typename T>
class QSafeQueue
{
public:
QSafeQueue();
void push_back(const T& data);
T pop_front();
private:
QList<T> m_oList;
QMutex m_oReadMutex;
QMutex m_oWriteMutex;
};
// QSafeQueue.cpp
template<typename T>
QSafeQueue<T>::QSafeQueue()
: m_oList(),
m_oMutex()
{
}
template<typename T>
void QSafeQueue<T>::push_back(const T &data)
{
m_oWriteMutex.lock();
m_oList.push_back(data);
m_oWriteMutex.unlock();
}
template<typename T>
T QSafeQueue<T>::pop_front()
{
if (m_oList.empty())
throw;
m_oReadMutex.lock();
T temp = m_oList.front(