zoukankan      html  css  js  c++  java
  • C++多线程同步技巧(二) ---事件

    简介

    Windows在线程控制方面提供了多种信号处理机制,其中一种便是使用 CreateEvent() 函数创建事件,然后使用信号控制线程运行。其中将事件变为有信号可使用 SetEvent() 函数,将事件信号复位(变为无信号)可使用 ResetEvent() 函数,信号可以配合 WaitForSingleObject() 函数对线程的同步进行控制,当有信号时,此函数便会放行;无信号时,此函数会将阻塞。

    提示: CreateEvent() 函数的参数 bManualReset 的含义是信号是否由人工复位,如果选择true,则信号必须手动采用ResetEvent() 函数进行复位操作。在这种情况下,可能会偶尔出现线程不同步的情况,问题出在可能同时会有多个线程穿过 WaitForSingleObject() 函数,导致复位失效,所以在这种情况下,为确保万无一失,我们一般会再添加一个限制条件,例如临界区互斥体;如果选择的是false,则当一个信号经过 WaitForSingleObject() 函数的时候,函数会自动将事件信号复位。

    代码样例

    • bManualReset参数为false
    ////////////////////////////////
    //
    // FileName : ThreadEventDemo.cpp
    // Creator : PeterZheng
    // Date : 2018/9/23 18:00
    // Comment : The usage of "CreateEvent"
    //
    ////////////////////////////////
    
    #pragma once
    
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <windows.h>
    
    using namespace std;
    
    DWORD WINAPI func1(LPVOID lpParam);
    DWORD WINAPI func2(LPVOID lpParam);
    
    HANDLE hEvent = NULL;
    unsigned int unCount = 0;
    
    DWORD WINAPI func1(LPVOID lpParam)
    {
    	while (true)
    	{
    		WaitForSingleObject(hEvent, INFINITE);
    		ResetEvent(hEvent);
    		if (unCount < 100)
    		{
    			unCount++;
    			Sleep(10);
    			cout << "Count: " << unCount << endl;
    			SetEvent(hEvent);
    		}
    		else
    		{
    			SetEvent(hEvent);
    			break;
    		}
    	}
    	return 0;
    }
    
    DWORD WINAPI func2(LPVOID lpParam)
    {
    	while (true)
    	{
    		WaitForSingleObject(hEvent, INFINITE);
    		ResetEvent(hEvent); // 重置事件为无信号状态
    		if (unCount < 100)
    		{
    			unCount++;
    			Sleep(10);
    			cout << "Count: " << unCount << endl;
    			SetEvent(hEvent); // 设置事件为有信号状态
    		}
    		else
    		{
    			SetEvent(hEvent);
    			break;
    		}
    	}
    	return 0;
    }
    
    int main(void)
    {
    	HANDLE hThread[2] = { NULL };
    	hEvent = CreateEvent(NULL, false, false, NULL); //创建一个匿名事件,当参数bManualReset设置为false时
    	hThread[0] = CreateThread(NULL, 0, func1, NULL, 0, NULL);
    	cout << "Thread-1 is RUNNING" << endl;
    	hThread[1] = CreateThread(NULL, 0, func2, NULL, 0, NULL);
    	cout << "Thread-2 is RUNNING" << endl;
    	SetEvent(hEvent);
    	WaitForMultipleObjects(2, hThread, true, INFINITE); //等待两个线程运行结束
    	CloseHandle(hThread[0]);
    	CloseHandle(hThread[1]);
    	CloseHandle(hEvent);
    	system("pause");
    	return 0;
    }
    
    • bManualReset参数为true
    ////////////////////////////////
    //
    // FileName : ThreadEventDemo.cpp
    // Creator : PeterZheng
    // Date : 2018/9/23 18:00
    // Comment : The usage of "CreateEvent"
    //
    ////////////////////////////////
    
    #pragma once
    
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <windows.h>
    
    using namespace std;
    
    DWORD WINAPI func1(LPVOID lpParam);
    DWORD WINAPI func2(LPVOID lpParam);
    
    HANDLE hEvent = NULL;
    HANDLE hMutex = NULL;
    unsigned int unCount = 0;
    
    DWORD WINAPI func1(LPVOID lpParam)
    {
    	while (true)
    	{
    		WaitForSingleObject(hEvent, INFINITE);
    		WaitForSingleObject(hMutex, INFINITE); //为互斥体上锁
    		ResetEvent(hEvent); // 重置事件为无信号状态
    		if (unCount < 100)
    		{
    			unCount++;
    			Sleep(10);
    			cout << "Count: " << unCount << endl;
    			SetEvent(hEvent); // 设置事件为有信号状态
    			ReleaseMutex(hMutex); //互斥体解锁
    		}
    		else
    		{
    			SetEvent(hEvent);
    			ReleaseMutex(hMutex);
    			break;
    		}
    	}
    	return 0;
    }
    
    DWORD WINAPI func2(LPVOID lpParam)
    {
    	while (true)
    	{
    		WaitForSingleObject(hEvent, INFINITE);
    		WaitForSingleObject(hMutex, INFINITE); //为互斥体上锁
    		ResetEvent(hEvent); // 重置事件为无信号状态
    		if (unCount < 100)
    		{
    			unCount++;
    			Sleep(10);
    			cout << "Count: " << unCount << endl;
    			SetEvent(hEvent); // 设置事件为有信号状态
    			ReleaseMutex(hMutex);
    		}
    		else
    		{
    			SetEvent(hEvent);
    			ReleaseMutex(hMutex);
    			break;
    		}
    	}
    	return 0;
    }
    
    int main(void)
    {
    	HANDLE hThread[2] = { NULL };
    	hEvent = CreateEvent(NULL, true, false, NULL); //创建一个匿名事件,当参数bManualReset设置为true时
    	hMutex = CreateMutex(NULL, false, NULL); //创建一个匿名互斥体
    	hThread[0] = CreateThread(NULL, 0, func1, NULL, 0, NULL);
    	cout << "Thread-1 is RUNNING" << endl;
    	hThread[1] = CreateThread(NULL, 0, func2, NULL, 0, NULL);
    	cout << "Thread-2 is RUNNING" << endl;
    	SetEvent(hEvent); // 设置事件为有信号状态
    	WaitForMultipleObjects(2, hThread, true, INFINITE); //等待两个线程运行结束
    	CloseHandle(hThread[0]);
    	CloseHandle(hThread[1]);
    	CloseHandle(hEvent);
    	CloseHandle(hMutex);
    	system("pause");
    	return 0;
    }
    

    参考文档

    【1】https://blog.csdn.net/s_lisheng/article/details/74278765

  • 相关阅读:
    初学mysql数据库
    类与对象课堂总结
    CNN网络的基本介绍(三)
    CNN网络的基本介绍(二)
    CNN网络的基本介绍(一)
    Android studio界面布局的简单介绍
    Android studio初见及结构分析
    JDBC实现Mysqual的增删改查
    BufferedReader统计TXT文本
    JAVA的异常处理
  • 原文地址:https://www.cnblogs.com/csnd/p/12896998.html
Copyright © 2011-2022 走看看