信号量---线程同步

   以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用。
抽象的来讲,信号量的特性如下:信号量是一个非负整数(车位数),所有通过它的线程/进程(车辆)都会将该整数减一(通过它当然是为了使用资源),当该整数值为零时,所有试图通过它的线程都将处于等待状态。在信号量上我们定义两种操作: 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\n",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

发布了13 篇原创文章 · 获赞 0 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/jonathanxqs/article/details/45117743