线程互斥html
多线程运行时,一般会访问同一个变量,同一个数据结构,或者同一段代码。所以,须要使用互斥技术来保护上述资源,确保多线程执行的正确性。安全
注:数据结构
咱们一般说某个函数是线程安全的,也就是由于该函数实现加入了线程互斥保护。多线程
4.一、QMutex函数
|
QMutex ( RecursionMode mode = NonRecursive )ui |
|
~QMutex ()this |
void.net |
lock ()线程 mutex加锁,若是当前其余线程已对该mutex加锁了,则该调用被阻塞直到其余线程释放该mutex。htm |
bool |
tryLock () mutex加锁,和lock不一样的是,若是当前其余线程已对该mutex加锁了,则该调用会当即返回,而不被阻塞。 |
bool |
tryLock ( int timeout ) 同tryLock,和tryLock不一样的是,若是当前其余线程已对该mutex加锁了,则该调用会等待一段时间,直到超时或者其余线程释放了mutex。 |
void |
unlock () mutex解锁,释放被锁住的资源。 |
Mutex有两种模式,用户能够在构造函数参数中指定。
Constant |
Value |
Description |
QMutex::Recursive |
1 |
In this mode, a thread can lock the same mutex multiple times and the mutex won't be unlocked until a corresponding number of unlock() calls have been made. 该模式下,一个线程能够对mutex屡次lock,直到相应次数的unlock,调用后,该mutex才真正被unlock。 |
QMutex::NonRecursive |
0 |
In this mode, a thread may only lock a mutex once. 该模式下,mutex只能被lock一次。 |
实例:
QMutex mutex;
int number = 6;
void method1()
{
mutex.lock();
number *= 5;
number /= 4;
mutex.unlock();
}
void method2()
{
mutex.lock();
number *= 3;
number /= 2;
mutex.unlock();
}
4.一、QMutexLocker
|
QMutexLocker ( QMutex * mutex ) |
|
|
QMutex * |
mutex () const |
void |
relock () |
void |
unlock () |
QMutexLocker其实是对QMutex使用的一种简化。
例如如下场景:
当某段代码存在多个分支,在对QMutex加锁后,须要在不一样的分支路径下都执行解锁操做,才能保证Mutex关联的资源能被其余线程继续访问, 不然就出现死锁。
QMutexLocker接收一个QMutex做为参数,当建立QMutexLocker对象时,就对关联的Mutex进行了Lock操做,直到该QMutexLocker对象被销毁,相关的QMutex才被Unlock。
实例:
直接使用QMutex:
int complexFunction(int flag)
{
mutex.lock();
int retVal = 0;
switch (flag) {
case 0:
case 1:
mutex.unlock();
return moreComplexFunction(flag);
case 2:
{
int status = anotherFunction();
if (status < 0) {
mutex.unlock();
return -2;
}
retVal = status + flag;
}
break;
default:
if (flag > 10) {
mutex.unlock();
return -1;
}
break;
}
mutex.unlock();
return retVal;
}
使用QMutexLocker:
int complexFunction(int flag)
{
QMutexLocker locker(&mutex);
int retVal = 0;
switch (flag) {
case 0:
case 1:
return moreComplexFunction(flag);
case 2:
{
int status = anotherFunction();
if (status < 0)
return -2;
retVal = status + flag;
}
break;
default:
if (flag > 10)
return -1;
break;
}
return retVal;
}
固然,使用QMutexLocker时,也须要注意QMutexLocker对象的生存周期,不然可能会出现锁时间过长,或者锁住的资源过多。
4.三、QReadLocker、QWriteLocker、QReadWriteLocker
还有一种场景,咱们所保护的资源是具备读写权限的,多个线程能够同时读取某个资源,可是当存在写操做,写操做未完成时,就不容许其余线程对该资源进行读操做。
|
|
|
QReadWriteLock ( RecursionMode recursionMode ) |
|
|
void |
lockForRead () |
void |
lockForWrite () |
bool |
|
bool |
tryLockForRead ( int timeout ) |
bool |
|
bool |
tryLockForWrite ( int timeout ) |
void |
unlock () |
|
QReadLocker ( QReadWriteLock * lock ) |
|
~QReadLocker () |
QReadWriteLock * |
readWriteLock () const |
void |
relock () |
void |
unlock () |
|
QWriteLocker ( QReadWriteLock * lock ) |
|
|
QReadWriteLock * |
readWriteLock () const |
void |
relock () |
void |
unlock () |
实例:
QReadWriteLock lock;
void ReaderThread::run()
{
...
lock.lockForRead();
read_file();
lock.unlock();
...
}
void WriterThread::run()
{
...
lock.lockForWrite();
write_file();
lock.unlock();
...
}
4.四、QSemaphore
和QMutex不一样的是,QSemaphore一次能够对多个资源进行保护,
例如如下场景:
某工厂只有固定仓位,生产人员天天生产的产品数量不一,销售人员天天销售的产品数量也不一致。当生产人员生产P个产品时,就一次须要P个仓位,当销售人员销售C个产品时,就要求仓库中有足够多的产品才能销售。
若是剩余仓位没有P个时,该批次的产品都不存入,当当前已有的产品没有C个时,就不能销售C个以上的产品,直到新产品加入后方可销售。
这就是典型的生产者-消费者问题。
|
QSemaphore ( int n = 0 ) |
|
~QSemaphore () |
void |
acquire ( int n = 1 ) |
int |
available () const |
void |
release ( int n = 1 ) |
bool |
tryAcquire ( int n = 1 ) |
bool |
tryAcquire ( int n, int timeout ) |
实例:
QSemaphore sem(5); // sem.available() == 5 默认有5个产品
sem.acquire(3); // sem.available() == 2 销售3个产品,成功
sem.acquire(2); // sem.available() == 0 销售2个产品成功
sem.release(5); // sem.available() == 5 生产5个产品
sem.release(5); // sem.available() == 10 生产10个产品
sem.tryAcquire(1); // sem.available() == 9, returns true 消费1个产品,成功
sem.tryAcquire(250); // sem.available() == 9, returns false 企图销售250个产品,失败,由于当前只剩下14个产品
4.五、QWaitCondition