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;
}

原文地址:https://www.cnblogs.com/PeterZ1997/p/9735331.html

时间: 2024-09-28 13:15:21

C++多线程同步技巧(二)--- 事件的相关文章

windows下多线程同步(利用事件对象,互斥对象,关键代码段)实现

一:利用事件实现线程同步 1.createthread函数的用法 hThread = CreateThread(&security_attributes, dwStackSize, ThreadProc,pParam, dwFlags, &idThread) ; HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAdd

Java多线程——同步(二)

在前面的一篇中,总结了如何使用Lock和Condition对象.我们先总结一下有关锁和条件的关键之处: 锁用来保护代码片段,任何时刻只能有一个线程执行被保护的代码. 锁可以管理试图进入被保护代码段的线程. 锁可以拥有一个或多个相关的条件对象. 每个条件对象管理那些已经进入被保护的代码段但还不能运行的线程. synchronized关键字 Java中的每一个对象都有一个内部锁:如果一个方法用synchronized关键字声明,那么对象的锁将保护整个方法.内部对象锁只有一个相关条件,wait方法添加

C++多线程同步技巧(一) --- 临界区

简介 C++中关于多线程的内容对于构建工程来说是至关重要的,C++本身也对关于多线程的操作提供了很好的支持.本章笔者就来介绍一下C++有关于多线程的重要知识点---临界区. 临界区的作用 线程就像是进程的影子,可以帮助进程几乎在同一个时间内执行更多的任务.但是由于线程不占有资源,所有的线程共享进程的资源,这样就导致多个线程在共享进程资源的时候会出现抢夺资源的情况,这些会被抢夺的资源就被称为是临界资源,例如打印机资源,文件读写,如果出现线程抢占,就会导致输出混乱.所以我们在进行对临界资源访问的时候

C++多线程同步技巧(三)--- 互斥体

简介 Windows互斥对象机制. 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问,在线程同步与保证程序单体运行上都有相当大的用处. 代码样例 //////////////////////////////// // // FileName : MutexDemo.cpp // Creator : PeterZheng // Date : 2018/10/23 21:27 // Comment : The usage of "Creat

【python标准库学习】thread,threading(二)多线程同步

继上一篇介绍了python的多线程和基本用法.也说到了python中多线程中的同步锁,这篇就来看看python中的多线程同步问题. 有时候很多个线程同时对一个资源进行修改,这个时候就容易发生错误,看看这个最简单的程序: import thread, time count = 0 def addCount(): global count for i in range(100000): count += 1 for i in range(10): thread.start_new_thread(ad

嵌入式 Linux进程间通信(十二)——多线程同步

嵌入式 Linux进程间通信(十二)--多线程同步 多线程编程中有三种线程同步机制:互斥锁.信号量.条件量.本文将使用生产者消费者问题编程实践三种线程同步方式. 生产者.消费者问题:生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费.消费者线程从缓冲区中获得物品,然后释放缓冲区.当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区.当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来. 一.互斥锁

C#多线程同步事件及等待句柄AutoResetEvent 和 ManualResetEvent

最近捣鼓了一下多线程的同步问题,发现其实C#关于多线程同步事件处理还是很灵活,这里主要写一下,自己测试的一些代码,涉及到了AutoResetEvent 和 ManualResetEvent,当然还有也简要提了一下System.Threading.WaitHandle.WaitOne .System.Threading.WaitHandle.WaitAny和System.Threading.WaitHandle.WaitAll ,下面我们一最初学者的角度来看,多线程之间的同步. 假设有这样的一个场

转---秒杀多线程第十二篇 多线程同步内功心法——PV操作上

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> <秒杀多线程第七篇经典线程同步互斥量Mutex> <秒杀多线程第八篇经典线程同步信号量Semaphore> <秒杀多线程第九篇经典线程同步总结关键段事件互斥量信号量> <秒杀多线程第十篇生产者消费者问题> <秒杀多线程第十一篇读者写者问题>

秒杀多线程第十二篇 多线程同步内功心法——PV操作上

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> <秒杀多线程第七篇经典线程同步互斥量Mutex> <秒杀多线程第八篇经典线程同步信号量Semaphore> <秒杀多线程第九篇经典线程同步总结关键段事件互斥量信号量> <秒杀多线程第十篇生产者消费者问题> <秒杀多线程第十一篇读者写者问题>