基于win32的多线程编程08 :线程之间的同步_信号量_Event事件

线程之间的同步(书接上文)

4 Semaphores 信号量
  • 系统核心对象

  • 与Mutex的区别在于

    • Mutex: 同一时间内只能有一个线程拥有操作的权力
    • Semaphores: 同一时间内可以有多个线程获得目标并操作…当然了,如果设置Semaphores的最大可获取对象为1的话,基本就等价于一个Mutex了
  • 使用方法(类似于Mutex)

1.	创建一个信号量:CreateSemaphore
HANDLE CreateSemaphoreA(
  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  LONG                  lInitialCount,		// 初始时,信号量的可用状态,大于0时,信号量可用
  LONG                  lMaximumCount,		// 信号量可用的最大数目
  LPCSTR                lpName
);
2.	打开一个已经存在的信号量:OpenSemaphore
3.	获得信号量的一个占有权:WaitForSingleObject、WaitForMultipleObjects 等一类等待的函数
4.  释放信号量的占有权:	ReleaseSemaphore;
5.	关闭信号量:CloseHandle;
  • 特点:
// Semaphores 可以跨进程使用,所以其名称对整个系统而言是全局的.所以命名不要过于普通
// 在“等待”一个 信号量 的时候,可以指定“结束等待”的时间长度;
// 执行效率相比用户对象慢一些
5 Event Objects 事件
  • Event 方式是最具弹性的同步机制,因为他的状态完全由你去决定,不会像 Mutex 和 Semaphores 的状态会由类似:WaitForSingleObject 一类的函数的调用而改变。互斥器和信号量的使用中,WaitForSingleObject等一类函数如果成功接收到指定的对象,那么互斥器和信号量的状态即发生改变
  • 使用方法:
1、创建一个事件对象:CreateEvent;
HANDLE CreateEventA(
  LPSECURITY_ATTRIBUTES lpEventAttributes,
  BOOL                  bManualReset,		// 手动:需要手动设置事件的状态,Wait...之后需要使用ResetEvent函数去设置事件状态位无信号的(未激发的)比较灵活
// 自动:计算机自动设置,Wait...函数执行后,自动变为无信号状态,类似Mutex这样
  BOOL                  bInitialState,		// 初始状态
  LPCSTR                lpName
);
2、打开一个已经存在的事件对象:OpenEvent;
3、获得事件的占有权:WaitForSingleObject 等函数(可能造成阻塞);
4、释放事件的占有权(设置为激发(有信号)状态,以让其他等待中的线程苏醒):SetEvent;
5、手动置为非激发(无信号)状态:ResetEvent
6、关闭事件对象句柄:CloseHandle;
  • 特点
1、系统核心对象,所以有安全描述指针,用完了要 CloseHandle 关闭句柄,这些是内核对象的共同特征;
2、因为是核心对象,所以执行速度稍慢(当然只是相比较而言);
3、因为是核心对象,而且可以命名,所以可以跨进程使用;
4、通常被用于 overlapped I/O (重叠IO)或被用来设计某些自定义的同步对象。

代码示例:

// 不要有恐惧心理,代码虽长,逻辑简单,静心看完,必有所获!!
#include <windows.h>
#include <stdio.h>

#define THREADCOUNT 4 

HANDLE ghGlobalWriteEvent; 			//全局写事件
HANDLE ghReadEvents[THREADCOUNT];	//全局读事件数组

DWORD WINAPI ThreadProc(LPVOID);	//线程处理函数的函数声明
// 创建事件和线程函数(主函数在下方)
void CreateEventsAndThreads(void) 	
{
    HANDLE hThread; 
    DWORD i, dwThreadID; 
    
// ==================================================================================
    // Create a manual-reset event object. The master thread sets 
    // this to nonsignaled when it writes to the shared buffer. 
	
	// 创建一个事件对象
    ghGlobalWriteEvent = CreateEvent( 
        NULL,               // default security attributes
        TRUE,               // manual-reset event
        TRUE,               // initial state is signaled
        TEXT("WriteEvent")  // object name
        ); 

    if (ghGlobalWriteEvent == NULL) 
    { 
        printf("CreateEvent failed (%d)\n", GetLastError());	// 创建失败
        return;
    }
    else if ( GetLastError() == ERROR_ALREADY_EXISTS )			// 已经存在
    {
        printf("Named event already exists.\n");
        return;
    }
    
    
// ====================================================================================  
    // Create multiple threads and an auto-reset event object 
    // for each thread. Each thread sets its event object to 
    // signaled when it is not reading from the shared buffer. 

	// 创建多线程,并且为每一个线程都创建一个自动模式的事件
    for(i = 0; i < THREADCOUNT; i++) 
    {
        // Create the auto-reset event
        ghReadEvents[i] = CreateEvent( 
            NULL,     // no security attributes
            FALSE,    // auto-reset event
            TRUE,     // initial state is signaled
            NULL);    // object not named

        if (ghReadEvents[i] == NULL) 
        {
            printf("CreateEvent failed (%d)\n", GetLastError());	// 创建失败
            return;
        }
		
		// 创建线程,并将事件句柄作为线程参数
        hThread = CreateThread(NULL, 
            0, 
            ThreadProc, 
            &ghReadEvents[i],  // pass event handle
            0, 
            &dwThreadID); 

        if (hThread == NULL) 
        {
            printf("CreateThread failed (%d)\n", GetLastError());
            return;
        }
    }
}

// 向Buffer中写数据的函数
void WriteToBuffer(VOID) 
{
    DWORD dwWaitResult, i; 

	// 先将全局写事件设为无信号,目的是阻止别的线程此时往里面写数据(也就达到了线程同步的目的)
    if (! ResetEvent(ghGlobalWriteEvent) ) 
    { 
        printf("ResetEvent failed (%d)\n", GetLastError());		//设置失败
        return;
    } 

    // Wait for all reading threads to finish reading
	// 然后等待所有的读Buffer线程完成任务
    dwWaitResult = WaitForMultipleObjects( 
        THREADCOUNT,   // number of handles in array
        ghReadEvents,  // array of read-event handles
        TRUE,          // wait until all are signaled
        INFINITE);     // indefinite wait一直等待

    switch (dwWaitResult) 
    {
        // All read-event objects were signaled
        case WAIT_OBJECT_0: 
            // TODO: Write to the shared buffer
            printf("Main thread writing to the shared buffer...\n");
            break;

        // An error occurred
        default: 
            printf("Wait error: %d\n", GetLastError()); 
            ExitProcess(0); 
    } 

    // Set ghGlobalWriteEvent to signaled
	// 写完数据之后,将全局写事件重新设置为有信号
    if (! SetEvent(ghGlobalWriteEvent) ) 
    {
        printf("SetEvent failed (%d)\n", GetLastError());
        ExitProcess(0);
    }

    // Set all read events to signaled
    for(i = 0; i < THREADCOUNT; i++) 
        if (! SetEvent(ghReadEvents[i]) ) 
        { 
            printf("SetEvent failed (%d)\n", GetLastError());
            return;
        } 
}

void CloseEvents()
{
    int i;

    for( i=0; i < THREADCOUNT; i++ )
        CloseHandle(ghReadEvents[i]);

    CloseHandle(ghGlobalWriteEvent);
}
//  主函数在这里啊!!!!!!!!!!!!!!!
void main()
{
    int i;

    // TODO: Create the shared buffer

    // Create the events and THREADCOUNT threads to read from the buffer

    CreateEventsAndThreads();

    // Write to the buffer three times, just for test purposes

    for(i=0; i < 3; i++)
        WriteToBuffer();

    // Close the events

    CloseEvents();
}

DWORD WINAPI ThreadProc(LPVOID lpParam) 
{
    DWORD dwWaitResult;
    HANDLE hEvents[2]; 

    hEvents[0] = *(HANDLE*)lpParam;  // thread's read event
    hEvents[1] = ghGlobalWriteEvent; // global write event

    dwWaitResult = WaitForMultipleObjects( 
        2,            // number of handles in array
        hEvents,      // array of event handles
        TRUE,         // wait till all are signaled
        INFINITE);    // indefinite wait

    switch (dwWaitResult) 
    {
        // Both event objects were signaled
        case WAIT_OBJECT_0: 
            // TODO: Read from the shared buffer
            printf("Thread %d reading from buffer...\n", 
                   GetCurrentThreadId());
            break; 

        // An error occurred
        default: 
            printf("Wait error: %d\n", GetLastError()); 
            ExitThread(0); 
    }

    // Set the read event to signaled

    if (! SetEvent(hEvents[0]) ) 
    { 
        printf("SetEvent failed (%d)\n", GetLastError());
        ExitThread(0);
    } 

    return 1;
}

// 节选自微软官网
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡与乌龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值