信号量 (Semaphores)
与互斥对象,互斥事件一样,信号量同样是一个内核对象。
信号量是一种用于控制对共享资源的访问的同步机制。它是一个计数器,用来表示可用资源的数量。信号量主要用于解决两个或多个进程或线程之间的同步和互斥问题。
信号量的操作主要有两个:
P操作(等待操作):如果信号量的值大于零,进程可以继续执行,信号量的值减一;如果信号量的值为零,则进程进入等待状态,直到信号量的值变为非零。
V操作(信号操作):释放资源,将信号量的值加一。如果有其他进程因信号量的值为零而等待,这些进程将被唤醒。
信号量可以是二进制的(只有0和1两个值),也可以是计数的(可以取多个正整数值),后者允许多个进程或线程同时访问同一资源的多个实例。
内核对象 (Kernel Objects)
内核对象是操作系统内核中的一个数据结构,它用于表示系统资源或系统状态。这些对象通常由操作系统内核管理,并提供一种机制,使得用户空间的程序可以通过一组定义良好的接口与这些资源或状态进行交互。内核对象可以代表硬件设备、文件、文件系统、进程、线程、或者其他系统资源。
内核对象的主要特点包括:
封装:内核对象隐藏了操作系统的复杂性,提供简单的接口给应用程序。
同步:许多内核对象提供同步机制,如互斥锁、事件、信号量等,帮助多个进程或线程安全地共享资源。
安全:内核对象通常包含访问控制列表(ACLs),确保只有拥有适当权限的用户或进程才能访问这些对象
函数
1、CreateSemaphore //创建或打开一个命名的或匿名的信号量对象的函数。
HANDLE CreateSemaphore(
LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
LONG lInitialCount,
LONG lMaximumCount,
LPCWSTR lpName
);
参数说明
lpSemaphoreAttributes:指向 SECURITY_ATTRIBUTES 结构的指针,这个结构决定了返回的句柄是否可以被子进程继承。如果为 NULL,则句柄不能被继承。
lInitialCount:信号量的初始计数值,指示信号量在创建时可用的资源数量。
lMaximumCount:信号量的最大计数值,指示信号量可以管理的最大资源数量。
lpName:信号量的名称。如果为 NULL,创建的是一个匿名信号量。如果非 NULL,则创建一个命名信号量,该名称可以被其他进程用来打开同一个信号量。
返回值
如果函数成功,返回值是新创建的信号量的句柄。
如果函数失败,返回值为 NULL。可以调用 GetLastError 函数来获取更多错误信息
2、WaitForSingleObject //用于等待指定的同步对象(如信号量、事件、互斥锁等)变为信号状态,即可用状态。当你对信号量使用这个函数时,它会检查信号量的当前计数值:
如果计数值大于0,函数立即返回,并将信号量的计数值减1,表示资源被占用。
如果计数值为0,调用线程将被置于等待状态,直到信号量的计数值变为大于0(通常是其他线程释放信号量),此时线程被唤醒,继续执行并将计数值减1。
3、ReleaseSemaphore//用于增加信号量的计数值,通常在资源使用完毕后调用。这个函数的调用通常发生在资源使用完毕后,以允许其他等待该信号量的线程可以继续执行。
第一个参数是信号量的句柄。
第二个参数是要增加的计数值,通常设置为1,表示释放一个资源单位。
第三个参数是一个可选的指针,用于接收信号量释放操作前的计数值(如果不需要这个信息,可以设置为 NULL)。
使用一个信号量实现线程同步
任务:卖鱼和买鱼 C++网络编程—多线程测试+互斥锁(2)
#include <Windows.h>
#include <stdio.h>
#include <process.h>
const int NUM_THREAD = 50;
unsigned WINAPI thread_buy(void* arg);
unsigned WINAPI thread_sell(void* arg);
long long is_succeed = 0;
//定义信号量的句柄
HANDLE hSemOne;
int main()
{
HANDLE tHandles[NUM_THREAD];
int i;
//创建第一个信号量hSemOne,总共资源为1,开放资源为1
hSemOne = CreateSemaphore(NULL, 1, 1, NULL);
printf("信号量线程同步测试\n");
for (i = 0; i < NUM_THREAD; i++)
{
if (i % 2)
{
tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, thread_buy, NULL, 0, NULL);
}
else
{
tHandles[i] = (HANDLE)_beginthreadex(NULL, 0, thread_sell, NULL, 0, NULL);
}
}
WaitForMultipleObjects(NUM_THREAD, tHandles, TRUE, INFINITE);
//释放信号量句柄资源
CloseHandle(hSemOne);
CloseHandle(hSemTwo);
// 遍历数组并关闭每个句柄
for (int i = 0; i < NUM_THREAD; i++) {
if (tHandles[i] != NULL) {
CloseHandle(tHandles[i]);
}
}
if (is_succeed == 0)
printf("交易成功!!!速速撤退!!!\n");
else
printf("交易失败!!!有差!!!\n");
system("pause");
return 0;
}
unsigned WINAPI thread_buy(void* arg)
{
//等待信号量释放资源
WaitForSingleObject(hSemOne, INFINITE);
for (int i = 0; i < 50000; i++)
{
is_succeed++;
}
//释放信号量的一个资源
ReleaseSemaphore(hSemOne, 1, NULL);
return 0;
}
unsigned WINAPI thread_sell(void* arg)
{
//等待信号量释放资源
WaitForSingleObject(hSemOne, INFINITE);
for (int i = 0; i < 50000; i++)
{
is_succeed--;
}
//释放信号量的一个资源
ReleaseSemaphore(hSemOne, 1, NULL);
return 0;
}