今天這個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~
留言列表