线程间的同步和通信

了解过了进程间的同步和通信,下面了解线程间的同步和通信。

相关知识点:进程和线程信号量机制进程同步互斥进程间通信

多线程OS通常提供多种同步机制。

互斥锁(mutex)

同进程互斥类似,它实现线程间对资源的互斥访问。

由于操作互斥锁的时间和空间开销都较低,因而较适合于高频度使用的关键共享数据和程序段。互斥锁有两种状态,即开锁(unlock)和关锁(lock)状态。

当一个线程需要读/写共享数据段时,首先判别该共享数据段所设置的mutex 的状态,如果它已处于关锁状态(不可用),则线程将被阻塞;如果 mutex 是处于开锁状态(可用),则将 mutex 关锁(设置标识)后便去读/写该数据段。在线程完成读/写后,必须再发出开锁命令将 mutex 开锁(恢复标识),同时还须将阻塞在该互斥锁上的一个线程唤醒,其它的线程仍被阻塞在等待 mutex 打开的队列上。

线程对资源的互斥访问 与 之前总结的临界资源、临界区一样。

上述读/写共享数据段的过程相当于记录型信号量,互斥锁是资源,资源数为1。关锁即资源数为0了。下图是记录型信号量的wait()和signal()描述,相当于互斥锁的关锁、开锁。

记录型信号量可能出现死锁,一个进程要求临界资源越多、死锁可能性越大。信号量机制中有详细总结。

 线程的互斥锁,也同样存在可能死锁的问题。

类似的:

有两个线程A、B。两个临界资源D、E,互斥锁分别是Dmutex、Emutex。

若A、B都需要D和E,按下面情况,无外界干预线程A、B即陷入死锁状态。同样需要资源越多,线程死锁可能也越大。

thread A: 对Dmutex关锁成功,再对Emutex关锁失败(需要E,但E被线程B持有),于是A阻塞,而Dmutex一直处于关锁状态

thread B: 对Emutex关锁成功,再对Dmutex关锁失败(需要D,但D被线程A持有),于是B阻塞,而Emutex一直处于关锁状态


条件变量

为了解决类似上述互斥锁中死锁问题引入了条件变量。

每一个条件变量通常都与一个互斥锁一起使用,亦即,在创建一个互斥锁时便联系着一个条件变量。

单纯的互斥锁用于短期锁定,主要是用来保证对临界区的互斥进入。而条件变量则用于线程的长期等待,直至所等待的资源成为可用的资源。

利用互斥锁和条件变量访问资源,大致描述如下:

//定义
mutex:互斥锁
resource:资源
condition:条件变量

///申请过程
Lock mutex
if(resource busy) 
    wait(condition);
mark resource as busy;
unlock mutex;

///释放过程
Lock mutex
mark resource as free;
unlock mutex;
wakeup(condition);

线程先对mudex关锁,进入临界区。若资源忙不可用,线程变转入等待队列(条件变量相关的队列),然后对mudex开锁;若资源空闲,标记资源为忙碌,再对mudex开锁。

使用资源的线程完成释放资源时,mudex关锁进入,标记资源空闲,再对mudex开锁,然后从条件变量的队列中唤醒一个线程。唤醒的就是之前进入等待中的线程,能够继续执行了。

类似管程机制中的条件变量。


信号量机制

进程同步工具:信号量机制。也可用于多线程OS中,实现多线程或进程之间的同步。

1) 私用信号量(private samephore)

当某线程需利用信号量来实现同一进程中各线程之间的同步时,可调用创建信号量的命令来创建一私用信号量。

数据结构存放在应用程序的地址空间中。私用信号量属于进程所有,OS并不知道私用信号量的存在。

2) 公用信号量(public semaphort)

公用信号量是为实现不同进程间各线程之间的同步而设置的。

由于它有着一个公开的名字供所有的进程使用,故而把它称为公用信号量。其数据结构是存放在受 保护的系统存储区中,由 OS 为它分配空间并进行管理,故也称为系统信号量。

原文地址:https://www.cnblogs.com/fanglongxiang/p/12921934.html