第七步:编写线程同步机制如互斥体(Mutex)、事件等

从本质上说,任何同步对象都可以看作是一个带等待队列的同步门。当这个门关闭的时候,试图访问这个对象的线程会被阻塞并进入等待队列。

 

Mutex对象就是按照这个原理来实现的:

 

一个Mutex对象包含一个Owner成员,用来判断当前的线程是不是这个Mutex对象的持有者。当一个线程试图访问一个Mutex对象时,这个Mutex对象用Owner成员判断当前的线程是不是这个Mutex对象的持有者。如果Owner成员等于当前线程的ID,当前线程是这个Mutex对象的持有者,访问这个Mutex对象成功。如果Owner成员为空,则把这个Mutex对象的Owner成员标为当前线程从而使当前线程获得这个Mutex对象的持有权,访问这个Mutex对象成功。如果Owner成员不为空并且不是当前线程,当前线程进入这个Mutex对象的等待队列并被阻塞。

 

当Mutex对象被释放时,Owner成员被清空。如果有线程被阻塞在等待队列中,这个线程将被resume并获得这个Mutex对象的持有权。此时,这个Mutex对象的Owner成员被标为这个线程的ID。

 

Event对象的实现方式和Mutex对象类似。主要的不同是决定阻塞的规则不同:Event对象是通过判断Signal成员是否为真来决定是否阻塞的,而Mutex对象是根据判断当前的线程是不是持有者来决定是否阻塞的。对于Event对象来说,当Signal成员为FALSE时,线程进入等待队列并被阻塞。否则,访问成功。

 

Event对象和Mutex对象还有一个不同:当Event对象的Signal成员被设置为TRUE时,所有等待线程都将被resume;而Mutex对象中只有第一个等待线程被resume。

 

在判断是否阻塞时,Semaphore对象可以被看作是一个带计数器的Event对象:每一次访问,计数器将减一。当计数器小于0时,Semaphore对象处于非signal状态,线程阻塞;否则,Semaphore对象处于signal状态,访问成功。当Semaphore对象收到一次信号时,计数器将加一,等待队列中的第一个被阻塞的线程将被resume。

 

这一步增加了三个模块,它们是mutex.c、event.c、semaphor.c,分别实现了这三种对象。另外,增加了一个list.h头文件,以实现一个整数链表。

 

下载这一步例子的源代码

 

下一步:编写任务间通信机制如消息队列等