C++进阶—>CreateEvent控制线程

1.概述

       事件对象就像一个开关:它只有两种状态---开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该线程睡眠,这样该线程占用的CPU时间就比较少。

2.CreateEvent函数

产生事件对象的函数如下: 
HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, //一般为NULL,属性
BOOL bManualReset, // 重置类型,手动重置还是 自动重置
BOOL bInitialState, // 初始状态,TRUE为有信号,FALSE为无信号
LPCTSTR lpName // 事件对象名  
);
该函数创建一个Event同步对象,如果CreateEvent调用成功的话,会返回新生成的对象的句柄,否则返回NULL。
参数说明:
lpEventAttributes 一般为NULL

bManualReset 创建的Event是自动复位还是人工复位.如果true,人工复位, 一旦该Event被设置为有信号,则它一直会等到ResetEvent()被调用时才会恢复为无信号; 如果为false,Event被设置为有信号,则当有一个wait到它的Thread时, 该Event就会自动复位,变成无信号. 如果想在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,您必须每次调用ResetEvent函数来清除事件的信号。

bInitialState 初始状态,true,有信号,false无信号


lpName 事件对象的名称。您在OpenEvent函数中可能使用。

3.Event相关

     一个Event被创建以后,可以用OpenEvent()来获得它的Handle,用CloseHandle()来关闭它(在主线程中使用CloseHandle()函数,很有可能导致子线程的Event对象信号控制机制失效,但需要将Event关闭,否则容易造成句柄泄漏问题,故合理使用关闭句柄函数);用SetEvent()或PulseEvent()来设置它使其有信号,用ResetEvent() 来使其无信号,用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号.

     SetEvent(HANDLE hEvent );   PulseEvent(HANDLE hEvent );   ResetEvent(HANDLE hEvent );

     PulseEvent()是一个比较有意思的使用方法,正如这个API的名字,它使一个Event 对象的状态发生一次脉冲变化,从无信号变成有信号再变成无信号,而整个操作是原子的.

对自动复位的Event对象,它仅释放第一个等到该事件的thread(如果有),而对于人工复位的Event对象,它释放所有等待的thread.


     这里有两个API函数用来修改事件对象的信号状态:SetEvent和ResetEvent。前者把事件对象设为”有信号”状态,而后者正好相反。
     在事件对象生成后,必须调用WaitForSingleObject来让线程进入等待状态,该函数的语法如下:

WaitForSingleObject(HANDLE hHandle,DWORD dwMilliseconds);

hHandle-->指向同步对象的指针。事件对象其实是同步对象的一种。

dwMilliseconds--> 等待同步对象变成”有信号”前等待的时间,以毫秒计。当等待的时间超过该值后无信号同步对象仍处于”无信号”状态,线程不再等待, WaitForSingleObject函数会返回WAIT_TIMEOUT。如果想要线程一直等待,请把该参数设为INFINITE(该值等于0xffffffff)为一直等待。

4.示例

#include "stdafx.h"
#include <windows.h>
#include <iostream>
#include <string.h>
#include <sstream>

using namespace  std;

#define NAME_LINE   40
HANDLE g_hMutex;
HANDLE g_hEvent;


//定义线程函数传入参数的结构体
typedef struct __TICKET
{
	int nCount;
	char strTicketName[NAME_LINE];

	__TICKET() : nCount(0)
	{
		memset(strTicketName, 0, NAME_LINE * sizeof(char));
	}
}TICKET;

typedef struct __THD_DATA
{
	TICKET* pTicket;
	char strThreadName[NAME_LINE];

	__THD_DATA() : pTicket(NULL)
	{
		memset(strThreadName, 0, NAME_LINE * sizeof(char));
	}
}THD_DATA;


//基本类型数据转换成字符串
template<class T>
string convertToString(const T val)
{
	string s;
	stringstream ss;
	ss << val;
	ss >> s;
	return s;
}

//售票程序
DWORD WINAPI SaleTicket(LPVOID lpParameter)
{

	THD_DATA* pThreadData = (THD_DATA*)lpParameter;
	TICKET* pSaleData = pThreadData->pTicket;
	while(pSaleData->nCount > 0)
	{
		//请求获得一个互斥量锁
		WaitForSingleObject(g_hEvent,INFINITE);
		WaitForSingleObject(g_hMutex, INFINITE);
		if (pSaleData->nCount > 0)
		{
			cout << pThreadData->strThreadName << "出售第" << pSaleData->nCount -- << "的票,";
			if (pSaleData->nCount >= 0) {
				cout << "出票成功!剩余" << pSaleData->nCount << "张票." << endl;
			} else {
				cout << "出票失败!该票已售完。" << endl;
			}
		}
		//Sleep(10);
		//释放互斥量锁
		ReleaseMutex(g_hMutex);
	}

	return 0L;
}



	//售票系统
int _tmain(int argc, _TCHAR* argv[])
{
	//创建一个互斥量
	g_hMutex = CreateMutex(NULL, FALSE, NULL);

	//创建一个控制量
	g_hEvent = CreateEvent(NULL,TRUE,TRUE,NULL);

	//初始化火车票
	TICKET ticket;
	ticket.nCount = 100;
	strcpy(ticket.strTicketName, "北京-->赣州");

	//定义售票口数组 和 线程数组
	const int THREAD_NUMM = 8;
	THD_DATA threadSale[THREAD_NUMM];
	HANDLE hThread[THREAD_NUMM];

	//循环售票
	for(int i = 0; i < THREAD_NUMM; ++ i)
	{
		threadSale[i].pTicket = &ticket;
		string strThreadName = convertToString(i);

		strThreadName = "窗口" + strThreadName;

		strcpy(threadSale[i].strThreadName, strThreadName.c_str());

		//创建线程
		hThread[i] = CreateThread(NULL, NULL, SaleTicket, &threadSale[i], 0, NULL);

		//请求获得一个互斥量锁
		if (i==0)
		{
			WaitForSingleObject(g_hMutex, 10);
			cout << "开始出售 " << threadSale[i].pTicket->strTicketName << " 的票..." << endl;
			//释放互斥量锁
			ReleaseMutex(g_hMutex);

		}

		if (i==6)
		{
			SetEvent(g_hEvent);
			//PulseEvent(g_hEvent);
			//ResetEvent(g_hEvent);
		}

		//关闭线程
		CloseHandle(hThread[i]);
		
	}


	//CloseHandle(g_hEvent);

	system("pause");

	return 0;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值