跳转至

线程同步

引入同步机制的原因

  1. 控制线程之间的资源同步访问,因为多个线程在共享资源时如果发生访问冲突通常会带来不正确的后果。例如,一个线程正在更新一个结构,同时另一个线程正试图读取同一个结构。结果,我们将无法得知所读取的数据是新的还是旧的,或者是二者的混合。
  2. 线程之间的动作以指定的次序发生,如一个线程需要等待由另外一个线程所引起的事件。

为了在多线程程序中解决同步问题,Windows提供了四种主要的同步对象。每种对象相对于线程有两种状态——信号状态(signal state)和非信号状态(nonsignalstate)。当相关联的同步对象处于信号状态时,线程可以执行(访问共享资源),反之必须等待。

四种同步对象

1、事件对象(Event)。

事件对象作为标志在线程间传递信号。一个或多个线程可等待一个事件对象,当指定的事件发生时,事件对象通知等待线程可以开始执行。它有两种类型:自动重置(auto-reset)事件和手动重置(manual-reset)事件。

2、临界区(Critical Section)。

临界区对象通过提供一个进程内所有线程必须共享的对象来控制线程。只有拥有那个对象的线程可以访问保护资源。在另一个线程可以访问该资源之前,前一个线程必须释放临界区对象,以便新的线程可以索取对象的访问权。

就是一段代码不能被并发执行,也就是,两个线程不能同时执行这段代码。

3、互斥量(Mutex Semaphore)。

互斥量的工作方式非常类似于临界区,只是互斥量不仅保护一个进程内为多个线程使用的共享资源,而且还可以保护系统中两个或多个进程之间的的共享资源。

4、信号量(Semaphore)。

信号量可以允许一个或有限个线程访问共享资源。它是通过计数器来实现的,初始化时赋予计数器以可用资源数,当将信号量提供给一个线程时,计数器的值减1,当一个线程释放它时,计数器值加1。当计数器值小于等于0时,相应线程必须等待。

从本质上讲,互斥量是信号量的一种特殊形式。

Windows/NT还提供了另外一种Windows95没有的同步对象:可等待定时器(Waitable Timer)。它可以封锁线程的执行,直到到达某一具体时间。这可以用于后台任务。同步问题是多线程编程中最复杂的问题。

信号量机制

信号量中,二元信号量,是一种最简单的锁。只有两种状态,占用和非占用。

信号量和互斥量的区别

信号量是允许并发访问的,也就是说,允许多个线程同时执行多个任务。信号量可以由一个线程获取,然后由不同的线程释放。

互斥量只允许一个线程同时执行一个任务。也就是同一个线程获取,同一个线程释放。

之前我对,互斥量只由一个线程获取和释放,理解的比较狭义,以为系统强制要求的意思,用 NSLock 实验发现可以在不同线程获取和释放,感觉很疑惑。

实际上,的确能在不同线程获取/释放同一个互斥锁,但是本来使用互斥锁,就是用在同一个线程中上锁和解锁。这里的意义更多在于代码使用上面。

这里的关键,就是理解信号量可以允许 N 个信号量允许 N 个线程并发地执行任务。