Qt数据同步与控制
1. qt多线程中的数据同步与互斥
qt实现互斥与同步的常用类有QMutex、QMutexLocker、QReadWriteLock、QReadLocker、QWriteLocker、QSemaphore、QWaitCondition。
2. 使用
-
QMutex,对同一代码块进行操作时用,但是会产生死锁
lock(),加锁,阻塞当前线程 unlock(),解锁 trylock(),如果已加锁,则立即返回,非阻塞
-
QMutexLocker,对死锁的优化,只用写一句话,在析构中自动解锁
用一个QMutex作为构造参数 QMutex _mutex; void Key::run() { QMutexLocker lock(&_mutex); key++; ... }
-
QReadWriteLock,对读写操作进行加锁
QReadWriteLock lock; void ReaderThread::run() { ... lock.lockForRead(); read_file(); lock.unlock(); ... } void WriterThread::run() { ... lock.lockForWrite(); write_file(); lock.unlock(); ... }
-
QSemaphore,信号量,可以获取多次,用来保护一定数量的同种资源。不能获取时,则阻塞线程直到满足条件。用完可以释放。解决生产-消费问题中二者同时分别操作缓冲区的不同部分,效率很高。初始化信号量为0,大于0则可用,否则不可用
const int DataSize = 1000; const int BufferSize = 100; extern char buffer[BufferSize]; extern QSemaphore freeBytes;//已消费,待生产 extern QSemaphore usedBytes; //已生产,待消费 class Producer : public QThread { Q_OBJECT public: Producer(QObject *parent=0); ~Producer(); void run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { freeBytes.acquire(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; usedBytes.release(); } } }; class Consumer : public QThread { Q_OBJECT public: Consumer(QObject *parent=0); ~Consumer(); void run() { QByteArray str; for (int i = 0; i < DataSize; ++i) { usedBytes.acquire(); str.append(buffer[i % BufferSize]); str.append("\n"); freeBytes.release(); } qDebug() <<str.toStdString().c_str(); } };
理解:生产者与消费者依次读写数据,生产者优先操作,每次生产一个,消费者也是每次消费一个。读写区域由作者自己控制,最好是环形缓冲区。
- QWaitCondition
需要与互斥锁配合使用,和信号量一样,可以用于环形缓冲区的生产与消费。
const int DataSize = 1000;
const int BufferSize = 100;
char buffer[BufferSize];
QWaitCondition bufferNotEmpty;
QWaitCondition bufferNotFull;
QMutex mutex;
extern int numUsedBytes;// = 0;
class Producer : public QThread
{
public:
Producer(QObject *parent = NULL) : QThread(parent)
{
}
void run() Q_DECL_OVERRIDE
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
for (int i = 0; i < DataSize; ++i) {
mutex.lock();
if (numUsedBytes == BufferSize)
bufferNotFull.wait(&mutex);
mutex.unlock();
buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4];
mutex.lock();
++numUsedBytes;
bufferNotEmpty.wakeAll();
mutex.unlock();
}
}
};
class Consumer : public QThread
{
Q_OBJECT
public:
Consumer(QObject *parent = NULL) : QThread(parent)
{
}
void run() Q_DECL_OVERRIDE
{
for (int i = 0; i < DataSize; ++i) {
mutex.lock();
if (numUsedBytes == 0)
bufferNotEmpty.wait(&mutex);
mutex.unlock();
fprintf(stderr, "%c", buffer[i % BufferSize]);
mutex.lock();
--numUsedBytes;
bufferNotFull.wakeAll();
mutex.unlock();
}
fprintf(stderr, "\n");
}
};
参考: