windows 使用 Semaphore 进行同步
使用Semaphore进行线程同步
#include <windows.h>
#include <stdio.h>
#define MAX_SEM_COUNT 2
#define THREADCOUNT 3
HANDLE ghSemaphore;
DWORD WINAPI ThreadProc(LPVOID);
int main(void)
{
HANDLE aThread[THREADCOUNT];
DWORD ThreadID;
int i;
// Create a semaphore with initial and max counts of MAX_SEM_COUNT
ghSemaphore = CreateSemaphore(
NULL, // default security attributes
MAX_SEM_COUNT, // initial count //初始化资源为2
MAX_SEM_COUNT, // maximum count //初始化资源最大数为2
NULL); // unnamed semaphore
if (ghSemaphore == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
// Create worker threads
for (i = 0; i < THREADCOUNT; i++)
{
aThread[i] = CreateThread(
NULL, // default security attributes
0, // default stack size
(LPTHREAD_START_ROUTINE)ThreadProc,
NULL, // no thread function arguments
0, // default creation flags
&ThreadID); // receive thread identifier
if (aThread[i] == NULL)
{
printf("CreateThread error: %d\n", GetLastError());
return 1;
}
}
// Wait for all threads to terminate
WaitForMultipleObjects(THREADCOUNT, aThread, TRUE, INFINITE);
// Close thread and semaphore handles
for (i = 0; i < THREADCOUNT; i++)
CloseHandle(aThread[i]);
CloseHandle(ghSemaphore);
return 0;
}
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
// lpParam not used in this example
UNREFERENCED_PARAMETER(lpParam);
DWORD dwWaitResult;
BOOL bContinue = TRUE;
dwWaitResult = WaitForSingleObject( //当线程使用WaitForSingleObject从ghSemaphore中获取到信号时,资源计数减少1,当ghSemaphore没有资源时,并且参数为INFINITE WaitForSingleObject会卡住
ghSemaphore, // handle to semaphore
INFINITE); // zero-second time-out interval
printf("Thread %d: wait succeeded\n", GetCurrentThreadId());
bContinue = FALSE;
// Simulate thread spending time on task
Sleep(5000);
// Release the semaphore when task is finished
if (!ReleaseSemaphore( // 该API使ghSemaphore的内部资源计数加1
ghSemaphore, // handle to semaphore
1, // increase count by one
NULL)) // not interested in previous count
{
printf("ReleaseSemaphore error: %d\n", GetLastError());
}
// The semaphore was nonsignaled, so a time-out occurred.
return TRUE;
}
上面的代码我启动了三个进程,为信号分配了两个资源,那么在程序开始时,有两个线程先通过WaitForSingleObject
获取到信号,此时信号的资源计数减到0,执行printf
,然后等5s,有一个线程调用了ReleaseSemaphore
,使资源计数加1,最后一个线程也执行printf
,等待5s,最后所有线程结束,程序退出
使用Semaphore进行进程同步
server.exe
#include <Windows.h>
#include <stdio.h>
#include <locale>
int main() {
setlocale(LC_ALL, "zh_CN.UTF-8");
TCHAR szCommandLine[] = TEXT("client.exe");//或者WCHAR
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = TRUE;
BOOL bRet = ::CreateProcess(NULL,szCommandLine,NULL,NULL,FALSE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi);
if (bRet)
{
LONG pre;
wchar_t wszPid[MAX_PATH] = { 0, };
wsprintf(wszPid, L"%d", pi.dwProcessId);
HANDLE semaphore = CreateSemaphore(0, 0, 1, wszPid);
wprintf(TEXT("按下Enter键发送信号"));
getchar();
ReleaseSemaphore(semaphore, 1, &pre);
wprintf(TEXT("信号已发送"));
WaitForSingleObject(pi.hProcess, INFINITE);
// 既然我们不使用两个句柄,最好是立刻将它们关闭
::CloseHandle(pi.hThread);
::CloseHandle(pi.hProcess);
CloseHandle(semaphore);
}
return 0;
}
client.exe
#include <Windows.h>
#include <stdio.h>
#include <locale.h>
int main() {
setlocale(LC_ALL, "zh_CN.UTF-8");
wchar_t wszPid[MAX_PATH] = {0,};
DWORD processId = GetCurrentProcessId();
wsprintf(wszPid, TEXT("%d"), processId);
HANDLE semaphore = OpenSemaphore(EVENT_ALL_ACCESS, FALSE, wszPid);
wprintf(TEXT("等待信号发送\n"));
WaitForSingleObject(semaphore, INFINITE);
wprintf(TEXT("获取到信号"));
getchar();
return 0;
}
server.exe
创建子进程client.exe
,获取子进程的pid
,创建信号,资源计数设置0,最大资源计数设置为1,然后getchar()
卡住界面,子进程client.exe
获取自己的pid
,打开信号,使用WaitForSingleObject
等待信号。server.exe
按任意键继续,使用ReleaseSemaphore
增加信号资源计数,子进程client.exe
,接收到信号,打印消息,最后程序退出