线程之间存在着相互制约的关系,具体可分为互斥和同步这两种关系。

    实现线程的互斥和同步常使用的类有QMutex, QMutexLocker, QReadWriteLocker, QReadLocker, QWriteLocker, QSemaphore, QWaitCondition

1. 举例说明

class Key
{
public:
    Key() { key = 0; }
    int createKey() { ++key; return key; }
    int value() const { return key; }
private:
    int key;
}

    这是实现生成从0开始递增且不允许重复的值的Key类。在多线程环境下,这个类是不安全的,因为存在多个线程同时修改私有成员key,其结果是不可预知的。虽然Key类产生key的函数createKey()只有一条语句执行修改成员变量key的值,但是C++的"++"操作符并不是原子操作,通常编译后,它将被展开成为以下三条机器命令:

  • 将变量值载入寄存器
  • 将寄存器中的值加1
  • 将寄存器中的值写回主存

    假设当前key的值为0,如果线程1和线程2同时将0值载入寄存器,执行加1操作并将加1后的值写回主存,则结果是两个线程的执行结果将互相覆盖,实际上仅进行了一次加1操作,此时的key值为1。

    为了保证Key类在多线程环境下正确执行,上面的三条机器指令必须串行执行且不允许中途被打断(原子操作),即线程1在线程2(或线程2在线程1)之前完整执行上述三条机器指令。

    实际上私有变量key是一个临界资源(Critical Resource, CR)。临界资源一次仅允许被一个线程使用,它可以是一块内存、一个数据结构、一个文件或者任何其他具有排他性使用的东西。在程序中,通常竞争使用临界资源。这些必须互斥执行的代码段称为“临界区”。临界区(代码段)实施对临界资源的操作,为了阻止问题的产生,一次只能有一个线程进入临界区。通常有相关的机制或方法在程序中加上"进入"或"离开"临界区等操作。如果一个线程已经进入某个临界区,则另一个线程就决不允许在此刻再进入同一个临界区。

2. 互斥量

    互斥量可通过QMutex和QMutexLocker类实现

 

3. 信号量

 

4. 线程等待与唤醒

 

posted on 2022-03-22 17:29  不再低调  阅读(310)  评论(0编辑  收藏  举报