• windows多线程(八) 信号量Semaphore


    如果你看到了这里,我就认为你已经对掌握了有关关键段 CriticalSection、互斥量Mutex和事件Event有关的内容,所以最基本的东西就不再介绍了。如果没有掌握上面说的内容,可以看这里:

    1. 关键段 CriticalSection
    2. 互斥量Mutex
    3. 事件Event

    一、信号量相关函数说明

    (一) 创建信号量CreateSemaphore
    1.函数原型
    
    HANDLE WINAPI CreateSemaphore(
    	    _In_opt_ LPSECURITY_ATTRIBUTES  lpSemaphoreAttributes,
    	    _In_     LONG lInitialCount,
    	    _In_     LONG lMaximumCount,
    	    _In_opt_ LPCWSTR lpName
    	    );
    
    
    
    2.参数说明
    • 第一个参数lpSemaphoreAttributes,表示安全属性。如果是NULL,就表示使用默认属性。

    • 第二个参数lInitialCount,信号量的初始数值,必须大于或等于0,并且小于或等于lMaximumCount

    • 第三个参数lMaximumCount,信号量的最大值,即最大并发数。

    • 第四个参数lpName,信号量的名字,是一个字符串,任何线程(或进程)都可以根据这一名称引用到这个信号量,这个值可以是NULL,表示产生一个匿名信号量。

    • 返回值: 如果成功就返回一个handle,否则传回NULL。

    (二) 打开信号量OpenSemaphore
    1.函数原型
    
    HANDLE WINAPI OpenSemaphore(
    	    _In_ DWORD dwDesiredAccess,
    	    _In_ BOOL bInheritHandle,
    	    _In_ LPCSTR lpName
    	    );
    
    
    
    2.参数说明
    • 第一个参数dwDesiredAccess,表示访问权限,一般传入SEMAPHORE_ALL_ACCESS。

    • 第二个参数bInheritHandle,表示信号量句柄继承性,一般传入True。

    • 第三个参数lpName,需要打开的信号量的名称。

    • 返回值: 如果成功就返回信号量handle,否则传回NULL。

    (三) 信号量解除锁定ReleaseSemaphore

    这个函数功能是实现信号量计数器增加一个值,该值通常是1,但不会超过创建信号量时指定的lMaximumCount

    1.函数原型
    
    BOOL WINAPI ReleaseSemaphore(
    	    _In_ HANDLE hSemaphore,
    	    _In_ LONG lReleaseCount,
    	    _Out_opt_ LPLONG lpPreviousCount
    	    );
    
    
    
    2.参数说明
    • 第一个参数hSemaphore,信号量的句柄。

    • 第二个参数lReleaseCount,表示信号量值增加的个数,必须大于0且不超过最大资源数,一般为1。

    • 第三个参数lpPreviousCount,传出先前信号量的计数值,设置为NULL表示不需要传出。

    • 返回值: 如果成功就返回True,否则传回False。

    (四) 关闭信号量

    由于信号量是一个内核对象,关闭时直接调用CloseHandle()就可以了。

    二、实例

    使用信号量同样可以实现线程的同步,实现每个线程按顺序依次给全局资源加一,代码如下:

    
    
    //  信号量演示
    
    #include<iostream>
    #include <windows.h>
    
    using namespace std;
    
    const int THREAD_NUM = 10;
    int g_Num = 0;
    CRITICAL_SECTION g_csVar; //创建关键段cs
    HANDLE g_ThreadSema;  //创建内核对象,用来初始化信号量
    
    DWORD WINAPI  Func(LPVOID);
    
    int main()
    {
    	InitializeCriticalSection(&g_csVar);
    	g_ThreadSema = CreateSemaphore(NULL, 0, 1, NULL); //创建匿名信号量,初始资源为零,最大并发数为1,
    
    	HANDLE handle[THREAD_NUM];
    	DWORD ThreadId[THREAD_NUM];
    	int i = 0;
    	while (i < THREAD_NUM)
    	{
    		handle[i] = CreateThread(NULL, 0, Func, &i, 0, &ThreadId[i]);
    		WaitForSingleObject(g_ThreadSema, INFINITE); //等待信号量资源数>0
    		i++;
    	}
    	WaitForMultipleObjects(THREAD_NUM, handle, true, INFINITE);
    	CloseHandle(g_ThreadSema); //销毁信号量
    	DeleteCriticalSection(&g_csVar);//销毁关键段cs
    	for (i = 0; i < THREAD_NUM; i++)
    	{
    		CloseHandle(handle[i]);
    	}
    	return 0;
    }
    
    
    DWORD WINAPI Func(LPVOID p)
    {
    	int nThreadNum = *(int*)p;
    	EnterCriticalSection(&g_csVar);
    	cout << "线程编号为: " << nThreadNum << " 全局资源值为:" << ++g_Num << endl;
    	LeaveCriticalSection(&g_csVar);
    	ReleaseSemaphore(g_ThreadSema, 1, NULL);  //信号量资源数加一
    	return 0;
    }
    
    

    运行结果如下所示:

  • 相关阅读:
    【Demo】QQ,github,微博第三方社交登录
    crontab执行时间和系统时间不一致
    CDN服务技术架构图
    【php】命名空间 和 自动加载的关系
    【运维工具】Git代码发布系统
    【ipv6惹的祸】curl 超时
    MySQL:动态开启慢查询日志(Slow Query Log)
    Virtualbox 虚拟机支持硬件摄像头
    网页取消快照、禁止抓取等meta标签功能
    ajax 跨域
  • 原文地址:https://www.cnblogs.com/ay-a/p/9130418.html
Copyright © 2020-2023  润新知