信號量---線程同步


  以一個停車場的運作為例。簡單起見,假設停車場只有三個車位,一開始三個車位都是空的。這時如果同時來了五輛車,看門人允許其中三輛直接進入,然后放下車攔,剩下的車則必須在入口等待,此后來的車也都不得不在入口處等待。這時,有一輛車離開停車場,看門人得知后,打開車攔,放入外面的一輛進去,如果又離開兩輛,則又可以放入兩輛,如此往復。
在這個停車場系統中,車位是公共資源,每輛車好比一個線程,看門人起的就是信號量的作用。
抽象的來講,信號量的特性如下:信號量是一個非負整數(車位數),所有通過它的線程/進程(車輛)都會將該整數減一(通過它當然是為了使用資源),當該整數值為零時,所有試圖通過它的線程都將處於等待狀態。在信號量上我們定義兩種操作: 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM