close

今天這個semaphore呢,之前就有聽過了

大部分是拿來跟mutex比較

不過在我看起來... 兩個似乎是不同作用的東西

大概就是... mutex是拿來保護資料的,semaphore是用來讓process(thread)間進行同步的

這個之後有機會再說吧,今天只看看semaphore

 

semaphore簡單說是個計數器,目的是讓process間進行同步的,如果要傳遞資料必須使用別的方式

我們來看一下wiki上的解釋:

號誌英語:Semaphore)又稱為旗號,是一個同步物件,用於保持在0至指定最大值之間的一個計數值。當執行緒完成一次對該semaphore物件的等待(wait)時,該計數值減一;當執行緒完成一次對semaphore物件的釋放(release)時,計數值加一。當計數值為0,則執行緒等待該semaphore物件不再能成功直至該semaphore物件變成signaled狀態。semaphore物件的計數值大於0,為signaled狀態;計數值等於0,為nonsignaled狀態.

其實我覺得寫的滿清楚的...

簡單說就是一個... 記數可以執行的thread(或是process)數量的計數器吧

 

都說是計數器了,所以會有兩種操作,分別是V(增加記數)和P(減少記數)

V操作又稱為signal(),P操作又稱為wait()

這麼想就很簡單了,當在一個process中執行P操作(wait())時,就是表示我要來跑critical section了

然後他就把計數器減1,占掉一個名額

等到他執行完critical section之後會執行V操作(signal()),表示用完了~

然後他就把計數器加1,把名額又還回去

 

所以說當這個計數器為0的時候,如果有人要執行P操作,表示他要去執行critical section,但是沒有名額啊?

那他就會一直停在這裡,等到有人把名額還回來為止

嗯... 這樣講或許還是有點不知道怎麼用吧,隨便舉個例好了

 

假設有個情境是這樣:

有個程式要計算出變數a和b兩個值加起來是多少,並且要把結果賦值給c

變數a和b分別會從其他的地方去取值過來,所以會有3個thread分別去做三件事情:

1. 取得a

2. 取得b

3. 計算出c,也就是a+b

那麼這樣會有什麼問題呢

在1和2尚未完成之前,是不能夠去進行3的

但那又是三個不同的thread啊,這時候semaphore就派上用場了

三個thread大概會長成這個樣子:

int a, b, c;

void geta()

{

    a = cala();

    semaphore.wait();

}

void getb()

{

    b = calb();

    semaphore.wait();

}

void calc()

{

    semaphore.signal();

    semaphore.signal();

    c = a+b;

}

嗯... 稍微再解釋一下好了,怕會有一些誤會

這三個function不會是有一個迴圈一值瘋狂執行的,而是有順序的分別執行

只是在實務上因為是不同的thread在執行,所以可能會有calc()比cala()和calb()先跑到的情況

這時候semaphore就會把它擋住,等到cala()和calb()都執行過了之後才會跑c=a+b

 

好吧這是我印象比較深的例子,接下來看一下實際上的用法吧

其實不同平台都有提供不同的function和不同的用法,也有很多的library有去實作,比如說boost(Qt也有),但觀念上都是一樣的

這邊就以linux的來舉例好了,以下是一個小範例:

/* Includes */
#include <unistd.h>     /* Symbolic Constants */
#include <sys/types.h>  /* Primitive System Data Types */
#include <errno.h>      /* Errors */
#include <stdio.h>      /* Input/Output */
#include <stdlib.h>     /* General Utilities */
#include <pthread.h>    /* POSIX Threads */
#include <string.h>     /* String handling */
#include <semaphore.h>  /* Semaphore */
 
/* prototype for thread routine */
void handler ( void *ptr );
 
/* global vars */
/* semaphores are declared global so they can be accessed
   in main() and in thread routine,
   here, the semaphore is used as a mutex */
sem_t mutex;
int counter; /* shared variable */
 
int main()
{
    int i[2];
    pthread_t thread_a;
    pthread_t thread_b;
     
    i[0] = 0; /* argument to threads */
    i[1] = 1;
     
    sem_init(&mutex, 0, 1);      /* initialize mutex to 1 - binary semaphore */
                                 /* second param = 0 - semaphore is local */
                                  
    /* Note: you can check if thread has been successfully created by checking return value of
       pthread_create */                                
    pthread_create (&thread_a, NULL, (void *) &handler, (void *) &i[0]);
    pthread_create (&thread_b, NULL, (void *) &handler, (void *) &i[1]);
     
    pthread_join(thread_a, NULL); // 特別標註一下,join是表示要等這個thread結束才會繼續執行下去,否則主程式結束了thread還沒結束怎麼行呢XD
    pthread_join(thread_b, NULL);
 
    sem_destroy(&mutex); /* destroy semaphore */
                   
    /* exit */ 
    exit(0);
} /* main() */
 
void handler ( void *ptr )
{
    int x;
    x = *((int *) ptr);
    printf("Thread %d: Waiting to enter critical region...\n", x);
    sem_wait(&mutex);       /* down semaphore */
    /* START CRITICAL REGION */
    printf("Thread %d: Now in critical region...\n", x);
    printf("Thread %d: Counter Value: %d\n", x, counter);
    printf("Thread %d: Incrementing Counter...\n", x);
    counter++;
    printf("Thread %d: New Counter Value: %d\n", x, counter);
    printf("Thread %d: Exiting critical region...\n", x);
    /* END CRITICAL REGION */   
    sem_post(&mutex);       /* up semaphore */
     
    pthread_exit(0); /* exit thread */
}

註解都寫得滿清楚了,這邊就記錄一下而已

裡面的sem_wait()就是P(wait)操作,sem_post()就是V(signal)操作

另外關於thread的使用... 找機會來寫一篇吧XD

這篇就簡單介紹一下semaphore了

 

很多地方都有參考 https://songlee24.github.io/2015/04/21/linux-IPC/,有興趣再去研究下

這篇就這樣了~ 881~

arrow
arrow
    全站熱搜

    頁頁頁六滴 發表在 痞客邦 留言(0) 人氣()