Win32多线程 -- 线程同步之信号量(Semaphores)

Semaphores是解决各种 producer/consumer问题的关键要素。这种问题会存有一个缓冲区,可能在同一时间内被读出数据或被写入数据。
理论可以证明,mutex 是 semaphore 的一种退化。如果你产生一个semaphore 并令最大值为1,那就是一个 mutex。也因此, mutex又常被称为binary semaphore。在许多系统中, semaphores 常被使用, 因为 mutexes可能并不存在。在Win32中semaphores 被使用的情况就少得多,因为 mutex 存在的缘故。

1. 产生信号量(Semaphore)

HANDLE CreateSemaphore(
	LPSECURITY_ATTRIBUTES lpAttributes,	// 安全属性, 可以设置NULL
	LONG lInitialCount,	// 初始值, [0, lMaximumCount]
	LONG lMaximumCount,	// 最大值, 这也就是在同一时间内能够锁住semaphore之线程的最多个数
	LPCTSTR lpName		// 名称, 其他线程或进程可以根据名称引用该信号量; NULL则产生无名称信号量
);

如果成功就传回一个handle, 否则传回NULL. 不论哪一种情况,GetLastError()都会传回一个合理的结果. 如果指定的semaphore名称已经存在,则该函数还是成功的, GetLastError()会传回ERROR_ALREADY_EXISTS.

2. 获得锁定

semaphore的现值代表的意义是目前可用的资源数, 如果semaphore的现值为1, 表示还有一个锁定动作可以成功; 如果现值为5, 就表示还有五个锁定动作可以成功. 每当一个锁定动作成功, semaphore的现值就会减1. 你可以使用任何一种Wait...()函数(例如 WaitForSingleObject())要求锁定一个semaphore. 因此, 如果semaphore的现值不为0, Wait...()函数会立刻返回.
一个线程可以反复调用Wait...()函数以产生新的锁定.  这和mutex绝不相同:拥有mutex的线程不论再调用多少次Wait...()函数, 也不会被阻塞住。
一旦semaphore的现值降到0, 就表示资源已经耗尽. 此时, 任何线程如果调用Wait...()函数, 必然要等待, 直到某个锁定被解除为止.

3. 解除锁定

为了解除锁定, 你必须调用ReleaseSemaphore(). 这个函数将semaphore的现值增加一个定额, 通常是1, 并传回semaphore的前一个现值.
Semaphore常常被用来保护固定大小的环状缓冲区(ring buffer)程序如果要读取环状缓冲区的内容, 必须等待 semaphore.
线程将数据写入环状缓冲区, 写入的数据可能不只一笔, 在这种情况下解除锁定时的semaphore增额应该等于写入的数据笔数.

BOOL ReleaseSemaphore(
	HANDLE hSemaphore,	
	LONG lReleaseCount,		// 现值的增额, 该值不可以是负值或0
	LPLONG lpPreviousCount	// 藉此传回semaphore原来的现值
);

ReleaseSemaphore()对于semaphore所造成的现值的增加, 绝对不会超过CreateSemaphore()时所指定的lMaximumCount.
ReleaseSemaphore()对于semaphore所造成的现值的增加, 绝对不会超过CreateSemaphore()时所指定的lMaximumCount.
lpPreviousCount 所传回来的是一个瞬间值. 你不可以把lReleaseCount加上*lpPreviousCount, 就当作是semaphore的现值, 因为其他线程可能已经改变了semaphore的值. 与mutex不同的是, 调用ReleaseSemaphore()的那个线程, 并不一定就得是调用Wait...()的那个线程, 任何线程都可以在任何时间调用ReleaseSemaphore(), 解除被任何线程锁定的semaphore.

4. 为什么semaphore要有一个初值

CreateSemaphore()的第二个参数是lInitialCount, 它的存在理由和CreateMutex()的bInitialOwner参数的存在理由是一样的. 如果你把初值设定为0, 你的线程就可以在产生semaphore之后进行所有必要的初始化工作. 待初始化工作完成后, 调用 ReleaseSemaphore()就可以把现值增加到其最大可能值.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值