Semaphore - 信号量的简单介绍与使用

article/2025/11/6 5:45:02

一、Semaphore使用

// Test_Semaphore.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <time.h>using namespace std;const int g_num = 3;
HANDLE g_semp[g_num] = { NULL };
HANDLE g_thrd[g_num] = { NULL };DWORD WINAPI thrdFunc1(__in LPVOID lpParameter);
DWORD WINAPI thrdFunc2(__in LPVOID lpParameter);
DWORD WINAPI thrdFunc3(__in LPVOID lpParameter);void test_func_1()
{clock_t t_start = clock();g_semp[0] = CreateSemaphore(NULL, 1, 1, NULL);g_semp[1] = CreateSemaphore(NULL, 1, 1, NULL);g_semp[2] = CreateSemaphore(NULL, 1, 1, NULL);g_thrd[0] = CreateThread(NULL, 0, thrdFunc1, (LPVOID)"thread 1", 0, NULL);g_thrd[1] = CreateThread(NULL, 0, thrdFunc2, (LPVOID)"thread 2", 0, NULL);g_thrd[2] = CreateThread(NULL, 0, thrdFunc3, (LPVOID)"thread 3", 0, NULL);clock_t t_point1 = clock();cout << "after all thread opened, usetime is " << t_point1 - t_start << " ms" << endl;::WaitForMultipleObjects(g_num, g_thrd, true, INFINITE);clock_t t_point2 = clock();cout << "after wait, usetime is " << t_point2 - t_start << "   waittime is " << t_point2 - t_point1 << " ms" << endl;CloseHandle(g_thrd[0]);CloseHandle(g_thrd[1]);CloseHandle(g_thrd[2]);CloseHandle(g_semp[0]);CloseHandle(g_semp[1]);CloseHandle(g_semp[2]);clock_t t_end = clock();cout << "after all handle close, usetime is " << t_end - t_start << "   closetime is " << t_end - t_point2 << " ms" << endl;
}int main()
{test_func_1();system("pause");return 0;
}DWORD WINAPI thrdFunc1(__in LPVOID lpParameter)
{DWORD start = GetTickCount();WaitForSingleObject(g_semp[0], INFINITE); //等待信号量Sleep(1000);cout << "Here is " << (char*)lpParameter << endl;ReleaseSemaphore(g_semp[0], 1, NULL); //释放信号量DWORD end = GetTickCount();cout << __FUNCTION__ << " exec end, usetime is " << end - start << " ms" << endl;return 0;
}
DWORD WINAPI thrdFunc2(__in LPVOID lpParameter)
{DWORD start = GetTickCount();WaitForSingleObject(g_semp[1], INFINITE); //等待信号量Sleep(8000);cout << "Here is " << (char*)lpParameter << endl;ReleaseSemaphore(g_semp[1], 1, NULL); //释放信号量DWORD end = GetTickCount();cout << __FUNCTION__ << " exec end, usetime is " << end - start << " ms" << endl;return 0;
}
DWORD WINAPI thrdFunc3(__in LPVOID lpParameter)
{DWORD start = GetTickCount();WaitForSingleObject(g_semp[2], INFINITE); //等待信号量Sleep(5000);cout << "Here is " << (char*)lpParameter << endl;ReleaseSemaphore(g_semp[2], 1, NULL); //释放信号量DWORD end = GetTickCount();cout << __FUNCTION__ << " exec end, usetime is " << end - start << " ms" << endl;return 0;
}

执行结果:

 

场景一:

       没有信号导致线程阻塞,可在以上代码的 thrdFunc1() 中做如下改动进行验证:

DWORD WINAPI thrdFunc1(__in LPVOID lpParameter)
{DWORD start = GetTickCount();WaitForSingleObject(g_semp[0], INFINITE); //等待信号量Sleep(1000);cout << "Here is " << (char*)lpParameter << endl;//ReleaseSemaphore(g_semp[0], 1, NULL); //释放信号量WaitForSingleObject(g_semp[0], INFINITE); //此时由于是没信号状态,执行线程1会阻塞在这里不退出DWORD end = GetTickCount();cout << __FUNCTION__ << " exec end, usetime is " << end - start << " ms" << endl;return 0;
}

 

执行结果:

 

场景二:

       在使用 ReleaseSemaphore 时,如果指定的数量将导致信号量的计数超过创建信号量时指定的最大计数,则计数不会更改,函数将返回FALSE。可在以上代码的 thrdFunc1() 中做如下改动进行验证:

DWORD WINAPI thrdFunc1(__in LPVOID lpParameter)
{DWORD start = GetTickCount();WaitForSingleObject(g_semp[0], INFINITE); //等待信号量Sleep(1000);cout << "Here is " << (char*)lpParameter << endl;ReleaseSemaphore(g_semp[0], 2, NULL); //释放信号量 > 预设的信号量最大计数为1,这里让其计数+2WaitForSingleObject(g_semp[0], INFINITE); //由于上面ReleaseSemaphore函数执行失败,不会改变信号量的计数,所以会阻塞在这里DWORD end = GetTickCount();cout << __FUNCTION__ << " exec end, usetime is " << end - start << " ms" << endl;return 0;
}

执行结果:

 


二、Semaphore属性

如何使用:

  • 创建一个信号量:CreateSemaphore;
  • 打开一个已经存在的信号量:OpenSemaphore;
  • 获得信号量的一个占有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数……(可能造成阻塞);
  • 释放信号量的占有权:ReleaseSemaphore;
  • 关闭信号量:CloseHandle;

 

固有特点(优点+缺点):

  • 是一个系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
  • 因为是核心对象,所以执行速度稍慢(当然只是相比较而言);
  • 因为是核心对象,而且可以命名,所以可以跨进程使用;
  • Semaphore 使用正确的情况下不会发生死锁;
  • 在“等待”一个 信号量 的时候,可以指定“结束等待”的时间长度;
  • 非排他性的占有,跟 Critical Sections 和 Mutex 不同,这两种而言是排他性占有,即同一时间内只能有单一线程获得目标并  拥有操作的权利。而 Semaphores 则不是这样,同一时间内可以有多个线程获得目标并操作!

 

信号量的使用规则:

  • 如果当前资源计数大于0,那么信号量处于触发状态;
  • 如果当前资源计数等于0,那么信号量处于未触发状态;那么系统会让调用线程进入等待状态。CreateSemaphore(NULL,0,1,NULL); 当第二个参数为0时,此时无信号,调用线程就会进入等待状态
  • 系统绝对不会让当前资源计数变为负数;
  • 当前资源计数绝对不会大于最大资源计数。

 


三、Semaphore相关接口介绍


typedef struct _SECURITY_ATTRIBUTES {DWORD nLength;LPVOID lpSecurityDescriptor;BOOL bInheritHandle;
} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;.../** Description*   Creates or opens a named or unnamed semaphore object.* Return value*   If the function succeeds, the return value is a handle to the semaphore object. If the named semaphore object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS.*   If the function fails, the return value is NULL. To get extended error information, call GetLastError.* Remarks*   The state of a semaphore object is signaled when its count is greater than zero, and nonsignaled when its count is equal to zero. */
WINBASEAPI _Ret_maybenull_ HANDLE WINAPI
CreateSemaphoreA(/* * A pointer to a SECURITY_ATTRIBUTES structure. * If this parameter is NULL, the handle cannot be inherited by child processes, and use the default security properties.*/_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,/** The initial count for the semaphore object. * This value must be greater than or equal to zero and less than or equal to lMaximumCount. */_In_     LONG lInitialCount,/** The maximum count for the semaphore object. * This value must be greater than zero.*/_In_     LONG lMaximumCount,/** The name of the semaphore object. * The name is limited to MAX_PATH characters. Name comparison is case sensitive.* If lpName is NULL, the semaphore object is created without a name.*/_In_opt_ LPCSTR lpName 
);WINBASEAPI _Ret_maybenull_ HANDLE WINAPI
CreateSemaphoreW(_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,_In_     LONG lInitialCount,_In_     LONG lMaximumCount,_In_opt_ LPCWSTR lpName 
);#ifdef UNICODE
#define CreateSemaphore  CreateSemaphoreW
#else
#define CreateSemaphore  CreateSemaphoreA
#endif // !UNICODE/** Description*   Increases the count of the specified semaphore object by a specified amount.* Return value*   If the function succeeds, the return value is nonzero.*   If the function fails, the return value is zero. *      To get extended error information, call GetLastError.* Remarks*   The state of a semaphore object is signaled when its count is greater than zero and nonsignaled when its count is equal to zero. *   Another use of ReleaseSemaphore is during an application's initialization. *     The application can create a semaphore with an initial count of zero. This sets the semaphore's state to nonsignaled and blocks all threads from accessing the protected resource. *     When the application finishes its initialization, it uses ReleaseSemaphore to increase the count to its maximum value, to permit normal access to the protected resource.*/
BOOL ReleaseSemaphore(/** A handle to the semaphore object. * The CreateSemaphore or OpenSemaphore function returns this handle.*/HANDLE hSemaphore,  /** The amount by which the semaphore object's current count is to be increased. * The value must be greater than zero. * If the specified amount would cause the semaphore's count to exceed the maximum count that was specified when the semaphore was created, the count is not changed and the function returns FALSE.*/LONG   lReleaseCount,/** A pointer to a variable to receive the previous count for the semaphore. * This parameter can be NULL if the previous count is not required.*/LPLONG lpPreviousCount
);

 

 

 


http://chatgpt.dhexx.cn/article/oDbm1hm3.shtml

相关文章

C++中多线程管理

1&#xff0c;函数1 CreateSemaphore 创建或打开一个信号量&#xff0c;信号可以理解为停车场&#xff0c;创建和增加信号&#xff0c;可以理解为创建一个停车场&#xff0c;和可以停放的汽车&#xff0c; 如下&#xff1a; CreateSemaphore(NULL, 2, 3, szSemaphoreA);//开…

lspci是如何工作的

目录 前言lspci那么系统是怎么知道每个PCIe设备具体是哪个厂商的哪种设备的&#xff1f; 前言 出于好奇&#xff0c;看了看lspci的工作原理&#xff0c;操作系统是怎么认识这么多PCIe设备的&#xff1b; lspci lspci用于查看当前系统所连接的所有PCI/PCIe设备&#xff1b; …

linux系统下怎么使用lspci,Linux系统之lspci命令介绍

lspci 顾名思义 就是显示所有的pci设备信息。pci是一种总线 而通过pci总线连接的设备就是pci设备了。如今 我们常用的设备很多都是采用pci总线了 如 网卡、存储等。下面就简单介绍下该命令。 lspci 显示所有的pci设备信息。包括设备的BDF 设备类型 厂商信息等。 lspci -t [BDF]…

lspci 和 setpci 的几种用法

1、指定pci 地址查看 2、查看vender id 3、查看 pcie 地址空间数据 4、修改 pci 地址空间的数据 setpci 读地址0xd0的值 setpci -v -s 01:00.0 d0.w 写地址0xd0的值 setpci -v -s 01:00.0 d0.w0x0101

lspci 详解 pci 拓扑结构 与 pci 树形结构

一、PCIE 拓扑结构 硬盘是大家都很熟悉的设备&#xff0c;一路走来&#xff0c;从HDD到SSD&#xff0c;从SATA到NVMe&#xff0c;作为NVMe SSD的前端接口&#xff0c;PCIe再次进入我们的视野。作为x86体系关键的一环&#xff0c;PCIe标准历经PCI&#xff0c;PCI-X和PCIe&#…

lspci命令

一 lspci命令详解 lspci命令&#xff1a;列出整个系统的PCIe总线和设备 使用方式有如下几种&#xff1a; 列出整个系统的PCIe总线和设备 列出指定PCIe设备的ID信息&#xff0c;即vendor ID和device ID 具体命令如下所示&#xff1a; 从上述信息可知&#xff0c;该设备的vend…

lspci

1) 以树的形式打印pci设备 # lspci -t -v 2) -n 显示vendor 和 device id &#xff0c; -m 向后兼容显示pci 设备的数据 # lspci -v -m -n -s 00:04.0 3&#xff09;通过hexdump 查看pci设备的配置空间 # hexdump /sys/devices/pci0000\:00/0000\:00\:05.0/config 4&#xf…

lspci命令整理

1. 作用&#xff1a; 显示当前主机的所有PCI总线信息 2. 常用指令&#xff1a; lspci -nn 第一列的数字&#xff1a; 总线编号(Bus Number)&#xff1a;设备编号&#xff08;Device Number&#xff09;&#xff1a;功能编号&#xff08;Function Number&#xff09; 第一个中…

request.getSession.setAttribute和request.setAttribute区别

【方法1】request.getSession.setAttribute 【方法2】request.setAttribute 相信很多初学的小伙伴对方法1和方法2&#xff0c;也充满了疑问&#xff0c;因为他们俩的作用都是把参数存入内存中&#xff0c;然后取出&#xff0c;或者被其他方法调用&#xff0c;但是不知道什么情…

setAttribute()和setProperty()

setAttribute()和setProperty() 学习笔记 初学习完setAttribute()和setProperty()后&#xff0c;在项目中使用时不太清楚原理&#xff0c;总是一知半解&#xff0c;最近又遇到关于这两个属性的笔试题&#xff0c;决定更加深入的去理解这两个属性。 setAttribue()&#xff1a;…

request.getParameter()、request.setAttribute()与request.getAttribute()的作用

1、request.getParameter()方法是获取通过类似post&#xff0c;get等方式传入的数据&#xff0c;即获取客户端到服务端的数据&#xff0c;代表HTTP请求数据。 2、request.setAttribute()方法是将request.getParameter()方法获取的数据保存到request域中&#xff0c;即将获取的…

HttpURLConnection.setRequestProperty的作用

设置http请求头 HttpURLConnection.setRequestProperty&#xff08;String key&#xff0c;String value&#xff09;; 这个我居然都忘记了&#xff0c;哎~真是岁数大了&#xff0c;心好累。。。 例如&#xff1a;下面就是一个完整的原始网络请求方式 HttpURLConnection …

一个破解压缩包密码的软件——ziperello

最近安了一个软件&#xff0c;解压还要密码&#xff0c;先是关注公众号啥的&#xff0c;分享链接啥的&#xff0c;然后顺着网友的吐槽找到这款软件。 读取准备文件会花费几个小时&#xff0c;但是最后破解几秒就好啦 下载链接 链接&#xff1a;https://pan.baidu.com/s/17TxQVX…

关于破解邮箱的一点心得

最近开始想更换一个好点的邮箱域名&#xff0c;因为本人名字可能比较火&#xff0c;163 126 foxmail主流邮箱的所有简写和拼写id都被占用&#xff0c;想购买又无路可走&#xff0c;所以把注意打到破解邮箱上&#xff0c;做了很多尝试。 首先在网上百度了很多破解邮箱的工具&…

压缩包密码破解工具

压缩包在解压文件的时候需要输入密码才能解压成功&#xff0c;遇到这种情况&#xff0c;需要一款压缩包破解工具将密码找到&#xff0c;才能继续解压文件 破解工具&#xff1a;okfone 压缩包解密大师 链接 支持rar、zip、7z格式的压缩文件解密 方法&#xff1a; 将文件添加…

压缩文件解压密码破解之fcrackzip

写在前面&#xff1a;网上对fcrackzip相关知识很多&#xff0c;我就不多哔哔了&#xff0c;我比较喜欢直接掏出重点少废话&#xff0c;写的花留呼哨一坨官方术语各种夸、没必要大家都挺忙的。 工具简介&#xff1a;fcrackzip是一款专门破解zip类型压缩文件密码的工具&#xff…

破解内网火狐所保存的邮箱账号和密码

进内网中&#xff0c;发现了个人单机装的有 foxmail 客户端,然后在 forxmail 安装目录下还发现存在数据目录&#xff0c;碰巧此人还可能用火狐登陆过邮箱&#xff0c;啧啧啧&#xff0c;那么本地就可能保存的有邮箱账号密码&#xff0c;这个文章就是我们怎么碰巧把密码接出来&a…

压缩包密码破解

压缩包的概念 任何一个文件存储在电脑上都有它的格式&#xff0c;例如文本格式像.txt .doc&#xff0c;图像格式 .jpg .tif .bmp等。 所有压缩也有压缩的格式&#xff0c;一般我们看到的压缩格式有 .rar&#xff0c; .zip 但主要压缩的作用就是让某一个文件占用空间小点。比如…

压缩包密码破解工具-ARCHPR

1、软件介绍 ARCHPR是一款强大又专业的密码恢复工具&#xff0c;软件主要是用于解密RAR压缩包的密码&#xff0c;它能够帮助用户轻松的解锁各种带有密码的压缩包文件。 官方简介&#xff1a; 解锁受密码保护的ZIP和RAR档案&#xff01;完美底层优化有助于更快地完成工作。能够…

暴力破解zip文件密码

先是用python写了一个&#xff0c;原理网上都有&#xff0c;我加了个界面&#xff0c;方便使用&#xff0c;同目录下放个pwd.txt&#xff0c;里面是密码列表&#xff0c;可以网上下载一些&#xff0c;或自己生成一个。 import zipfile from threading import Thread from tkint…