一、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
);



















