目录
描述
使用
线程不安全
线程安全
释放锁问题
其他的锁
条件变量和信号量
描述
多线程程序太复杂了
在C/C++ 和 Linux中,我们为了保证线程安全,简单的方式就是加锁
?
为此 Qt? 也封装了自己的一套锁管理
使用
线程不安全
我们先测验一下线程不安全的情况,先自定义一个类,等会要重写 QThread 类
thread.h?
thread.cpp
一个简单的累加?
运行发现,结果并不是我们所想象中的那样
线程安全
对++ 进行加锁,在CPU指令之中,++操作一共有三个指令,本身不是原子的,所以有线程不安全的问题,我们对涉及到修改的代码块进行加锁,保证线程安全
创建一共静态的锁对象,确保是使用同一把锁
运行正常,累加到了应有的数值?
?
释放锁问题
关于锁的释放,是有可能忘记释放的,忘记 unlock
在临界区之中,由于可能存在 判断,异常之类的操作,可能会导致锁没有释放
?
在C++释放内存中也有这样的问题存在,因此C++ 引入了智能指针,来解决内存释放和锁释放的问题
在出花括号区域的时候,lock_guard会自动调用析构,来释放 锁?
?
Qt 为了锁的释放也参考了这种做法,创建了 mutexLocker
使用如下,和C++之中的 std::lock_guard 使用方式一样
不建议和C++混着用锁相关函数
其他的锁
Qt中还有很多其他的锁,诸如读写锁,在特定的场景有着很好的发挥
QReadWriteLocker、QReadLocker、QWriteLocker
QReadWriteLock 是读写锁类,?于控制读和写的并发访问。 QReadLocker ?于读操作上锁,允许多个线程同时读取共享资源。 QWriteLocker ?于写操作上锁,只允许?个线程写?共享资源。
条件变量和信号量
条件变量
????????在多线程编程中,假设除了等待操作系统正在执?的线程之外,某个线程还必须等待某些条件满?才能执?,这时就会出现问题。这种情况下,线程会很?然地使?锁的机制来阻塞其他线程,因为这只是线程的轮流使?,并且该线程等待某些特定条件,?们会认为需要等待条件的线程,在释放互斥锁或读写锁之后进?了睡眠状态,这样其他线程就可以继续运?。当条件满?时,等待条件的线程将被另?个线程唤醒。 在 Qt 中,专?提供了 QWaitCondition类 来解决像上述这样的问题。 ????????特点:QWaitCondition 是 Qt 框架提供的条件变量类,?于线程之间的消息通信和同步。 ?????????途:在某个条件满?时等待或唤醒线程,?于线程的同步和协调
伪代码如下,使用过程也大致如下?
QMutex mutex;
QWaitCondition condition;
//在等待线程中
mutex.lock();
//检查条件是否满?,若不满?则等待
while (!conditionFullfilled())
{
condition.wait(&mutex); //等待条件满?并释放锁
}
//条件满?后继续执?
//...
mutex.unlock();
//在改变条件的线程中
mutex.lock();
//改变条件
changeCondition();
condition.wakeAll(); //唤醒等待的线程
mutex.unlock();
信号量
????????有时在多线程编程中,需要确保多个线程可以相应的访问?个数量有限的相同资源。例如,运?程序的设备可能是?常有限的内存,因此我们更希望需要?量内存的线程将这?事实考虑在内,并根据可?的内存数量进?相关操作,多线程编程中类似问题通常?信号量来处理。信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作,?且可以跟踪可?资源的数量。 ????????特点:QSemaphore 是 Qt 框架提供的计数信号量类,?于控制同时访问共享资源的线程数量。 ?????????途:限制并发线程数量,?于解决?些资源有限的问题
伪代码,使用过程如下?
QSemaphore semaphore(2); //同时允许两个线程访问共享资源
//在需要访问共享资源的线程中
semaphore.acquire(); //尝试获取信号量,若已满则阻塞
//访问共享资源
//...
semaphore.release(); //释放信号量
//在另?个线程中进?类似操作