信号量(Semaphore)
信号量是内核对象,使用几个形象的例子,进行描述.
1 假设有5个位置,而外面有很多人要进来,那么当5个位置被人占用了
后,其他人就必须排队等待,每个人使用时间不同,5个占用的位置,其中有两个完成了,那么,排队的人中,最前面的两个人进行可以使用,但是最多就是5个人同时能够使用,这就是信号量.
2 例如我们在服务器中创建了一个线程池,它由5个线程组成,也就意味着,最多同时处理5个请求,一旦超过5个,那么请求就放入缓冲中,当一个或多个请求(最多5个)完成后,那么从缓冲中拿出其他的请求进行处理.
信号量的特点:
1 信号量同来对资源进行计数
2 包含一个使用计数器,一个最大资源计数器,和一个当前资源计数器
3 最大资源计数器用来控制最大的子元素
4 当前资源计数器表示当前可用的资源数量
触发规则和当前资源计数器是相关的。
触发规则:
1 如果当前资源>0则信号量处于触发状态
2 如果当前资源=0,则信号量处于未触发状态
3 系统绝对不会让当前资源技术变为负值
4 当前资源计数绝对不会大于最大资源计数
运行流程:
1 假设我们创建了一个信号量,它的最大资源计数为5,且当前资源计数
也为5(一般都是在初始化过程中间最大的资源计数值和当前资源计数值是相同的) 由于当前资源计数器大于0,说明信号量处于触发状态.
2 为了获取对被保护的资源的访问权,线程会调用wait函数,并转入信号量的句柄,在内部,等待函数会检测当前资源计数器 技术,如果大于
0(大于0触发状态)那么等待函数会将当前资源计数器减1并让调用线程
继续运行,如果等于0(未触发状态)那么系统会让线程进入等待状态(不消化cpu),当另外一个线程将信号量的当前资源计数递增时,系统会
记得哪些线程在等待,使他们编程可调度状态(并相应的递减当前资源计数)
3 线程通过releaseSemaphore来递增信号量的当前资源计数器.
来看代码:
全局变量 HANDLE g_hSem;
创建一个信号量CreateSemaphore(NULL,2,2,NULL);
参数1 windows。。权限
参数2 代表当前资源计数值
参数3 最大资源计数器,表示信号量同时可以管理2个线程
参数4 对象名...
应为创建的时候,当前的资源计数大于0,所以他是触发状态的。
创建5个线程,用5个线程竞争两个位置,体现一下竞争的激烈.
case WM_CREATE: { //系统中基于对话框字体的高度 int cyChar = HIWORD(GetDialogBaseUnits()); thrParams4.hwnd = hWnd; thrParams4.cyChar = cyChar; //创建信号量 g_hSem = CreateSemaphore(NULL, 2, 2,NULL); HANDLE handleEmployee1 = CreateThread(NULL, 0, ThrEmployeeProc1, &thrParams4, 0, NULL); HANDLE handleEmployee2 = CreateThread(NULL, 0, ThrEmployeeProc2, &thrParams4, 0, NULL); HANDLE handleEmployee3 = CreateThread(NULL, 0, ThrEmployeeProc3, &thrParams4, 0, NULL); HANDLE handleEmployee4 = CreateThread(NULL, 0, ThrEmployeeProc4, &thrParams4, 0, NULL); HANDLE handleEmployee5 = CreateThread(NULL, 0, ThrEmployeeProc5, &thrParams4, 0, NULL); //关闭线程句柄 CloseHandle(handleEmployee1); CloseHandle(handleEmployee2); CloseHandle(handleEmployee3); CloseHandle(handleEmployee4); CloseHandle(handleEmployee5); } case WM_DESTROY: //关闭信号量 CloseHandle(g_hSem); PostQuitMessage(0); break;
来看一下线程函数吧.
DWORD WINAPI ThrEmployeeProc1(LPVOID lp) { PPARAMS param4 = static_cast<PPARAMS>(lp); //等待这个信号量 永远阻塞 如果信号量的 当前资源计数 大于0 就触发 反悔 WaitForSingleObject(g_hSem,INFINITE); //当他返回的时候 当前资源计数会 减1 //休眠2秒 Sleep(2000); //获取当前毫秒数 DWORD dwCurTime = GetTickCount(); //获得DC HDC hdc = GetDC(param4->hwnd); //显示文本 BOOL bF = TextOut(hdc, 0, (g_iLine4++)*param4->cyChar, _T("员工线程1正在使用公司上网"), lstrlen(_T("员工线程1正在使用公司上网"))); //释放dc ReleaseDC(param4->hwnd,hdc); //循环10秒退出 while (true) { if ((GetTickCount() - dwCurTime) > 1000 * 10) { HDC hdc = GetDC(param4->hwnd); SetTextColor(hdc, RGB(255, 0, 0)); TextOut(hdc, 0, (g_iLine4++)*param4->cyChar, _T("员工线程1已经没有使用公司上网"), lstrlen(_T("员工线程1已经没有使用公司上网"))); ReleaseDC(param4->hwnd, hdc); break; } Sleep(1000); } //释放信号量 信号量句柄 穿进去 并且 // 1代表加1 当前资源计数器+1 可以+2 +3 但是现在加1最合适 // 最后一个参数是反回上一次资源计数器的数量 大部分情况下 不需要这个东西 ReleaseSemaphore(g_hSem,1,NULL); return 0; }
效果:
我们发现 这个上网的数量,是通过信号量被控制住了,每次最多
可以有两个员工可以上网。
有不懂的连续我qq:2438746951
交流群:140066160
源代码地址:http://down.51cto.com/data/2329794
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。