Linux系統中的信號量機制

一、信號量的定義:linux

struct semaphore {
    spinlock_t lock;
    unsigned int count;
    struct list_head wait_list;
};

在linux中,信號量用上述結構體表示,咱們能夠經過該結構體定義一個信號量。數組

二、信號量的初始化:併發

可用void sema_init(struct semaphore *sem, int val);直接建立,其中val爲信號量初值。也能夠用兩個宏來定義和初始化信號量的值爲1或0:函數

DECLARE_MUTEX(name)	:	定義信號量name並初始化爲1
DECLARE_MUTEX_LOCKED(name)	:	定義信號量name並初始化爲0

還能夠用下面的函數初始化:code

void init_MUTEX(struct semaphore *sem);	 //初始化信號量的值爲1
void init_MUTEX_LOCKED(struct semaphore *sem);	//初始化信號量的值爲0

三、信號量的原子操做:隊列

p操做:進程

  • void down(struct semaphore *sem); //用來獲取信號量,若是信號量值大於或等於0,獲取信號量,不然進入睡眠狀態,睡眠狀態不可喚醒
  • void down_interruptible(struct semephore *sem); //用來獲取信號量,若是信號量大於或等於0,獲取信號量,不然進入睡眠狀態,等待信號量被釋放後,激活該程。
  • void down_trylock(struct semaphore *sem); //試圖獲取信號量,若是信號量已被其餘進程獲取,則馬上返回非零值,調用者不會睡眠

v操做:ci

  • void up(struct semaphore *sem); //釋放信號量,並喚醒等待該資源進程隊列的第一個進程

四、經典同步問題的解決方案:資源

  • 生產者和消費者問題:

a、單緩衝區問題描述:生產者向消費者提供產品,它們共享一個有界緩衝區,生產者向其中投放產品,消費者從中取得產品。同時,每一個進程都互斥的佔用CPU。假定生產者和消費者是互相等效的,只要緩衝區未滿,生產者就能夠把產品送入緩衝區,相似的,只要緩衝區未空,消費者即可以從緩衝區中取走產品並消費它。生產者—消費者的同步關係將禁止生產者向已滿的緩衝區中放入產品,也禁止消費者從空的緩衝區中獲取產品get

問題分析: 須要定義兩個信號量,一個用於互斥訪問緩衝區,另外一個用於生產者與消費者之間的同步。s1=1; s2=0;

僞代碼:

生產者進程            

while(1)                                         
{                                       
    printf(「I'm producing!\n」);                                        
    down_interruptible(&s1);                                         
    printf(「I'm putting a product into the buffer\n」);          
    up(&s1);                   
    up(&s2);                
}

消費者進程

while(1)  
{
    down_interruptible(&s2);
    down_interruptible(&s1);
    printf(「I'm getting a product\n」);
    up(&s1);
    printf(「I'm consuming a product\n」);
}

b、多生產者、多消費者、n個緩衝區

問題描述:有一羣生產者進程在生產產品,並將這些產品提供給消費者進程去消費。爲使生產者進程與消費者進程併發執行,在二者之間設置了n個緩衝區,生產者將產品放入一個緩衝區中,消費者能夠從一個緩衝區中取走產品去消費。要求生產者進程與消費者進程必須保持同步,即不容許生產者進程向一個滿的緩衝區放產品,也不容許消費者從一個空的緩衝區取產品。

問題分析:該問題貌似比a問題複雜的多,首先咱們定義一個數組buffer[n],來表示n個緩衝區,還須要定義兩個變量:in 表示要存入的緩衝區的下標,out表示要取產品的緩衝區的下標。定義三個信號量:s1用於實現對緩衝池的互斥操做,empty表示空緩衝區的個數,full表示滿緩衝區的個數。初值:in=out=0; s1=1; full=0; empty=n;

僞代碼以下:

生產者進程                                                                  

while(1)                                                                          
{                                                                                      
    printf(「I'm producing!\n」);                                                   
    down_interruptible(&empty);                                           
    down_interruptible(&s1);                                                   
    printf(「I'm putting a product into the buffer[in]\n」);                 
                                                                                                          
    in = (in+1)%n;                                                                                
    up(&s1);                                                                                      
    up(&full);                                                                     
}

消費者進程

  • 哲學家進餐問題

    while(1) { down_interruptible(&full); down_interruptible(&s1); printf(「I'm getting a product from buffer[out]\n」); out = (out+1)%n; up(&empty); printf(「I'm consuming a product\n」); }

問題描述:五個哲學家共用一個圓桌,分別坐在周圍的五張椅子上,在圓桌上有五隻碗和五隻筷子,他們交替進行思考和進餐。哲學家飢餓時便試圖取最靠近他的兩隻筷子,當同時得到兩隻筷子時即可用餐,用餐完畢後放下筷子。

問題分析: 五隻筷子爲臨界資源,定義包含五個元素的信號量數組來實現對筷子的互斥使用。chopstick[5],五個信號量的初值都爲1。

僞代碼:

第i(i=0,1,2,3,4)個哲學家進程:

while(1)
{
          down_interruptible(&chopstick[i]);
          down_interruptible(&chopstick[(i+1)%5]);
          printf(「I'm eating!\n」);
          up(&chopstick[i]);
          up(&chopstick[(i+1)%5);
}
  • 讀者寫者問題:

問題描述:一個文件可被多個進程共享,reader進程讀取該文件,而writer進程負責寫文件,容許多個reader進程同時讀取文件,但不容許一個writer進程和其餘reader進程或writer進程同時訪問文件。

問題分析:進程對文件互斥訪問的實現可藉助一個信號量就能夠搞定,可是咱們須要引入一個count變量來記錄reader進程的個數,對這個變量的訪問也是互斥的,因此也須要引入一個信號量。定義信號量rs實現對count的互斥訪問,定義ws實現對文件的互斥訪問。兩信號量初值都爲1

僞代碼:

reader進程                             	
{                                                                                          
        down_interruptible(&rs);                                                                                                                                                                                                   
        count++;
        up(&rs);  
        printf(「I'm reading!\n」);   
       down_interruptible(&rs);
       count--;
       if(count == 0){
               up(&ws);
        }
        up(&rs);
}       

 writer進程
 {
    down_interruptible(&ws);           
    if (count == 0){ 
        printf(「I'm writing!\n」);
        down_interruptible(&ws);                                     
    } 
    up(&ws);
}
相關文章
相關標籤/搜索