zoukankan      html  css  js  c++  java
  • 信号量---线程同步

      以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
    在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。
    抽象的来讲,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程/进程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: Wait(等待) 和 Release(释放)。当一个线程调用Wait操作时,它要么得到资源然后将信号量减一,要么一直等下去(指放入阻塞队列),直到信号量大于等于一时。Release(释放)实际上是在信号量上执行加操作,对应于车辆离开停车场,该操作之所以叫做“释放”是因为释放了由信号量守护的资源。

      可以用信号量实现主线程与子线程间的同步,而用关键段实现子进程间的互斥:

    第一个 CreateSemaphore

    函数功能:创建信号量

    函数原型:

    HANDLE CreateSemaphore(

      LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

      LONG lInitialCount,

      LONG lMaximumCount,

      LPCTSTR lpName

    );

    函数说明:

    第一个参数表示安全控制,一般直接传入NULL

    第二个参数表示初始资源数量。

    第三个参数表示最大并发数量。

    第四个参数表示信号量的名称,传入NULL表示匿名信号量。

     

    第二个 OpenSemaphore

    函数功能:打开信号量

    函数原型:

    HANDLE OpenSemaphore(

      DWORD dwDesiredAccess,

      BOOL bInheritHandle,

      LPCTSTR lpName

    );

    函数说明:

    第一个参数表示访问权限,对一般传入SEMAPHORE_ALL_ACCESS。详细解释可以查看MSDN文档。

    第二个参数表示信号量句柄继承性,一般传入TRUE即可。

    第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个信号量。

     

    第三个 ReleaseSemaphore

    函数功能:递增信号量的当前资源计数

    函数原型:

    BOOL ReleaseSemaphore(

      HANDLE hSemaphore,

      LONG lReleaseCount,  

      LPLONG lpPreviousCount 

    );

    函数说明:

    第一个参数是信号量的句柄。

    第二个参数表示增加个数,必须大于0且不超过最大资源数量。

    第三个参数可以用来传出先前的资源计数,设为NULL表示不需要传出。

     

    注意:当前资源数量大于0,表示信号量处于触发,等于0表示资源已经耗尽故信号量处于末触发。在对信号量调用等待函数时,等待函数会检查信号量的当前资源计数,如果大于0(即信号量处于触发状态),减1后返回让调用线程继续执行。一个线程可以多次调用等待函数来减小信号量。 

     

    最后一个 信号量的清理与销毁

    由于信号量是内核对象,因此使用CloseHandle()就可以完成清理与销毁了。

      

    #include<stdio.h>
    #include<process.h>
    #include<windows.h>
    
    volatile  long g_nLoginCount;
    const int THREAD_NUM = 10;
    volatile  long g_num;
    
    CRITICAL_SECTION g_thread;
    HANDLE g_Semaphore; //信号量
    
    unsigned int __stdcall ThreadFun(void *pPM){
        int thread_id=*((int *)pPM);
        
        ReleaseSemaphore(g_Semaphore,1,NULL);//信号量++
        
        Sleep(50);
        
        EnterCriticalSection(&g_thread);
        g_num++;
        Sleep(0);
        printf("ID : %d  全局:%d
    ",thread_id,g_num);
        LeaveCriticalSection(&g_thread);
        
        return 0;
    }
    
    int main(){
    
        InitializeCriticalSection(&g_thread);
        g_Semaphore = CreateSemaphore(NULL,0,1,NULL);//当前0个资源,最大允许1个同时访
        g_nLoginCount = 0;
        g_num=0;
    
        HANDLE handle[THREAD_NUM];
    
        int num=20;
    
        g_nLoginCount = 0;
        for(int i = 0;i < THREAD_NUM; i++){
            handle[i] = (HANDLE)_beginthreadex(NULL,0,ThreadFun,&i,0,NULL);
            WaitForSingleObject(g_Semaphore,INFINITE);
        }
    
        WaitForMultipleObjects(THREAD_NUM,handle,TRUE,INFINITE);
    
        CloseHandle(g_Semaphore);
        DeleteCriticalSection(&g_thread);
        return 0;
    }

    总结:信号量与事件的区别在与,信号量的大小可以设置,而事件可以看做是“大小为1的信号量”。

    参考:http://blog.csdn.net/morewindows/article/details/7481609

  • 相关阅读:
    设计模式之装饰器模式
    设计模式之原型模式
    设计模式之策略模式
    设计模式之适配器模式
    设计模式之注册模式
    wordpress中add_action和add_filter
    工厂模式
    设计模式之命令链模式
    观察者模式
    工厂模式
  • 原文地址:https://www.cnblogs.com/huhuuu/p/3588077.html
Copyright © 2011-2022 走看看