C++系列 --- 信号量同步详解

一、线程同步

1、线程同步

多线程程序设计大多会涉及线程间相互通信。主线程在创建工作线程以后,工作线程之间还需要通过通信机制来协同工作。一种比较好的方法就是使用事件内核对象。

事件内核对象是一种用于多线程同步和他们之间的通信手段。

同步可以保证在一个时间内只有一个线程对某个共享资源有控制权。 

2、汽车东西走向与南北走向协调的问题

 

二、事件内核对象

1、事件内核对象

事件内核对象是一种抽象的对象,它也有未受信和受信两种状态,可以使用WaitForSingleObject函数等待其变成受信状态。不同于其他内核对象的一些函数可以使实践对象在这两种状态之间转换。可以把时间对象看成是一个设置在Windows内部的一个标志。它的状态设置和测试工作由Windows来完成。

时间对象包含3个成员:

nUsageCount:使用计数

bManualReset:是否人工重置

bSignaled:是否受信 

2、基本函数

 

//使用CreateEvent函数创建事件对象:
HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, // 用来定义事件对象的安全属性
BOOL bManualReset, // 指定是否需要手工重置事件对象为受信状态
BOOL bInitialState,  // 指定事件对象创建时的初始状态
LPCWSTR lpName); // 事件对象的名称  

//根据lpName对象的名字查询,返回事件对象句柄:
HANDLE OpenEvent(DWORD dwDesiredAccess, // 指定想要的访问权限
BOOL bInheritHandle, // 指定返回句柄是否被继承
LPCWSTR lpName); // 要打开的事件对象的名称

BOOL SetEvent(HANDLE hEvent); // 将事件状态设置为受信状态
BOOL ReSetEvent(HANDLE hEvent); // 将事件状态设置为未受信状态

三、实例

1、多线程同步,实现两个线程交互打印A、B

#include <stdio.h>
#include <windows.h>
#include <process.h>

HANDLE g_hEventEW,g_hEventNS; // 东西与南北事件

UINT _stdcall ProcessA(LPVOID lpParam)
{
	while (true)
	{
		WaitForSingleObject(g_hEventEW, INFINITE);
		printf("A\n");
		SetEvent(g_hEventNS);
		Sleep(200);
	}
	return 0;
}

UINT _stdcall ProcessB(LPVOID lpParam)
{
	while (true)
	{
		WaitForSingleObject(g_hEventNS, INFINITE);
		printf("B\n");
		SetEvent(g_hEventEW);
		Sleep(200);
	}
	return 0;
}

int main()
{
	HANDLE H[2];
	H[0] = (HANDLE)_beginthreadex(NULL, 0, ProcessA, NULL, 0, NULL);
	H[1] = (HANDLE)_beginthreadex(NULL, 0, ProcessB, NULL, 0, NULL);
	
	// 问题1:主线程如何调用A,B两个线程
	// 东西向的先走
	g_hEventEW = CreateEvent(NULL, FALSE, TRUE, NULL);
	g_hEventNS = CreateEvent(NULL, FALSE, FALSE, NULL);

	WaitForMultipleObjects(2, H, TRUE, INFINITE); // 无限等待

	// 问题2:A、B如何交互打印

	system("pause");
	return 0;
}

2、实验结果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章