现在的位置: 首页 > 综合 > 正文

白话windows多线程同步之信号量

2019年03月10日 ⁄ 综合 ⁄ 共 1426字 ⁄ 字号 评论关闭

     引子:我们还是从需求说起。不喜欢别人一开始就贴代码,讲函数参数的含义,这可吓到不少人。咱重点是讲技术的思路和应用场合,咱也是小菜一个,文章有错误的地方还请您海涵。

假设我们在开发一个服务器进程,其中分配了一块缓存保存客户的请求。我们已经在代码中把缓存的大小固定死了,这样服务器进程在任一时刻最多只能保存3个客户的请求。如果一个新的客户试图在尚有3个请求未处理的时候来连接服务器,那么它将被拒绝并得到一个错误的信息,表示服务器正忙,请客户稍后重试。信号量内核对象将适用这种情况。下面用代码模拟这个需求:

#include "stdafx.h"
#include <iostream>
using std::cout ;
using std::cin ;
#include <Windows.h>
#include <process.h>

HANDLE g_Sem = NULL ;

DWORD WINAPI Fun(LPVOID lp)
{
	char c = *((char*)lp) ;
	delete lp ;
	WaitForSingleObject(g_Sem, INFINITE) ;
	int nId = c ;
	printf("The Thread Id %c is doing something now!!!\n", nId) ;
	Sleep(3000) ;
	printf("The Thread Id %c is Finished!!!\n", nId) ;
	ReleaseSemaphore(g_Sem, 1, NULL) ;
	return 0 ;
}

int _tmain(int argc, _TCHAR* argv[])
{
	g_Sem = CreateSemaphore(NULL, 3, 5, NULL) ;
	int nCount ;
	cout<<"Enter Require Thread nums:" ;
	cin>>nCount ;
	HANDLE thrd  ;
	for (int i = 0 ; i < nCount ; i++){
		char* c = new char ;
		*c = 'A' + i ;
		thrd = CreateThread(NULL, 0, Fun, (LPVOID)c, 0, NULL) ;
	}

	while(TRUE)
	{
		 //必须有这段代码,否则主线程退出了整个程序就退出了,后面的过程就无法实现了  
	}
	return 0;
}

代码当分析:

主线程会根据输入创建n个线程,然而根据我们的需求,只能最多同时让3个线程获取资源,所以在线程执行函数里面要做访问限制保护措施,这次我们等待的是信号量内核对象:WaitForSingleObject(g_Sem, INFINITE) 。那么信号量又有什么规则呢?

规则如下:

①如果当前资源计数大于0,那么信号量处于触发状态,等于0则处于未触发状态

②系统绝对不会让当前资源计数变为负数

③当创建信号量时,当前资源计数大于最大资源计数,则创建失败

当输入有6个线程在请求时的效果如下图:


请看,6个请求最开始只能有3个请求得到响应。当一个请求完成后,一个新的请求马上有得到响应。

注意,请求完成之后,必须调用ReleaseSemaphore(g_Sem, 1, NULL) 函数来增加当前资源计数,否则后面的请求永远得不到响应,不信你试试。咦?明明是ReleaseSemaphore,怎么叫增加资源计数?是的,我们只有这样看才能比较顺利的理解这样的情景。实际上,信号量内核对象除了包含一个使用计数外,还包含另外两个32位值:一个最大资源计数和一个当前资源计数。最大资源计数表示信号量可以控制的最大资源数量,当前资源计数表示信号量当前可用资源的数量。

抱歉!评论已关闭.