Semaphore原理與操作說明

Semaphore原理與操作說明

作者/王宜倫

[發表日期:2012/5/5]


甚麼是semaphore (信號)

Semaphore是Edsger W. Dijkstra於1960年代末期所設計的一種程式設計架構。Semaphore是一個variable (變數)或是abstract data type (抽象資料型別),提供平行運算環境中,控制多個process (程序)或thread(執行緒)存取共享資源的能力,Semaphore可以用於紀錄某一特定資源剩下多少數目可使用;process或thread透過semaphore可以安全的使用共享資源,若特定資源已使用完時,會需要等待資源被釋放。雖然semaphore在防止deadlock或race condition方面是一個很有用的工具,但是程式使用semaphore運作上並無法保證一定不會遇到這些問題。

Semaphore包含兩種:binary semaphore(二進位信號)和counting semaphore(計數信號)。

一、binary semaphore(二進位信號)

binary semaphore值只能是0或1,在邏輯上相當於一個mutex(互斥鎖)。mutex使用上與binary semaphore具有相同功能,但是,mutex主要設計是防止兩個process同時間執行相同的一段code或存取同一資料,而binary semaphore設計上則是限制同時間存取同一資源;很多應用上mutex具有owner(擁有者)的概念,只有鎖住mutex的process,才具有解鎖的權限;相對的,semaphore並無此限制。

二、counting semaphore(計數信號)

counting semaphore值依據semaphore.h的SEM_VALUE_MAX (semvmx)定義。也有作業系統稱作general semaphore。

Semaphore的運作原理

Edsger W. Dijkstra的模型與鐵路操作有關:假設某段鐵路是單線的,因此,一次只允許一列火車通過;semaphore用於協調同步通過該軌道的火車,火車在進入單一軌道之前必須等待信號燈變為允許通行的狀態,火車進入軌道後,必須改變信號燈狀態,防止其他火車進入該軌道;火車離開這段軌道時,必須再次更改信號燈的狀態,以便允許其他火車進入軌道。

或是類似圖書館的研究室使用,假設有10間研究室(SEM_VALUE_MAX=10),若學生要使用研究室便需要向櫃檯申請,櫃檯會記錄有多少間研究室使用中,若10間研究室都被申請使用後,且仍有學生要申請使用,該學生必須等待有其他學生離開,空出研究室後,才能進入使用,該櫃檯就扮演semaphore的角色。

在電腦系統中,信號燈(semaphore)以整數來表示,可用兩種操作行為來說明:

一、V operation:V()會將semaphore的值加1,signal函數或是sem_post()。
二、P operation:P()會將semaphore的值減1,wait函數或是sem_wait()。

P和V的意義來自荷蘭文(Edsger W. Dijkstr為荷蘭人),V代表verhogen,其意思是增加,P代表portmanteau prolaag,其意思是嘗試減小。在P operation中,semaphore在減小之前必須為正,確保semaphore值不為負,並且比該值減小之前小1;在P和V operation中,必須在沒有干擾的情況下進行運算,亦即每個P或V operation必須具備atomic operation特性,該operation是不可分割的(all or nothing behavior)。

從semaphore概念上來說,counting semaphore為一個非負整數計數器,通常用來協調process或thread對共享資源的存取。semaphore value可用來表示可用資源的數目,可在初始化時將semaphore value設為可用資源的數目,然後,在使用資源時減1,在釋放資源時加1;若為負數時,表示資源不足,要存取共享資源的process或thread會被阻擋(block),需要等待semaphore value變為正整數時,才可存取共享資源。實務上,也可將semaphore初始值設為1,使用該資源時加1,釋放資源時減1,若無法再加1時(signal或post回傳-1),表示已無資源可使用,程式需針對此錯誤進行處理;部分作業系統當使用超過最大值時(SEM_VALUE_MAX)會發生overflow(溢位),變為負數,表示資源不足。

由於semaphore並無強制由同一個process或thread來獲取和釋放,因此semaphore可用於非同步事件通知;同時,由於semaphore包含狀態,因此可以非同步方式使用,而不用像條件變數那樣要求獲取mutex。但是,semaphore的效率不如mutex。

Semaphore可以是無名稱的(unnamed)或是有名稱的(named),unnamed semaphore可供單一process或不同process使用,依據初始化時設定決定,named semaphore則在不同process間同步共享資源。

Semaphore的使用

此章節以POSIX semaphore來說明semaphore的初始化、V operation、P operation與結束。關於POSIX semaphore的特性說明如下:

  • POSIX semaphore是標準的counting semaphore,使用sem_post()執行V opeation,sem_wait()執行P operation。
  • POSIX semaphore的最大值於limits.h中所定義,如下:
    #define _POSIX_SEM_VALUE_MAX 32767
    define中所定義的最大值32767為POSIX標準規範的值,亦即實際各種作業平台的semaphore最大值至少需為32767才符合POSIX規範;實際最大值可由sysconf()所設定:
    long sem_value_max = sysconf(_SC_SEM_VALUE_MAX);
    目前實際程式測試,各種主要作業系統的SEM_VALUE_MAX如下:
    Windows 2008 : 2,147,483,647
    RHEL 5.0 : 2,147,483,647
    CentOS : 2,147,483,647
    Solaris 10 : 2,147,483,647
    HP-UX 11iv3 : 2,147,483,647
    IBM AIX 6.1 : 32,767
  • 一個semaphore並非被單一thread所擁有,亦即一個thread對semaphore執行sem_wait()時,另一thread可以執行sem_post()。但是作業系統在實作時,同一時間點僅能執行其中一個指令,以維持semaphore的一致性。
  • 當建立一semaphore時,須設定semaphore的初始值,且初始值須符合:0 ? initial value ? SEM_VALUE_MAX
  • Semaphore動作執行成功會回傳0,失敗會回傳 -1,並可將error number存放在errno,C的function perror(const char* string)可將errno的值存放在一字串,可將字串再列印到stderr。
  • sem_trywait(sem_t* sem)不會block呼叫的thread:
    • 若semaphore value大於0,會將semaphore減1,立即完成此動作並回傳。
    • 若semaphore value小於等於0,會立即回傳錯誤EAGAIN,說明semaphore value非大於0。

一、Semaphore操作函數

後續說明sem_init()、sem_post()、sem_wait()、sem_trywait()與sem_destroy()使用方式。
  • sem_init():初始化semaphore

    語法:
    int sem_init(sem_t *sem, int pshared, unsigned int value);

    #include
    sem_t sem;
    int pshared;
    int rc;
    int value;
    pshared =0;
    value =1;
    rc = sem_init(&sem, pshared, value);

    說明:
    (1)第一個參數為semaphore的位址,第二個參數為設定semaphore是否可讓不同process使用,第三個參數為semaphore初始值。
    (2)pshared的值為0,不能在process之間共用semaphore,僅能供process的所有thread使用;如果pshared的值不為0,則可以在process之間共用信號。
    (3)初始的semaphore值為1。
    (4)多個thread決不能初始化同一個semaphore。
    (5)不得對其他thread正在使用的semaphore重新初始化。

    sem_init()成功完成後會回傳0,若回傳值為-1則表示執行發生錯誤,如果出現下任一情況,該函數將失敗並回傳對應值:
    -EINVAL:參數值超過了SEM_VALUE_MAX。
    -ENOSPC:始化semaphore所需的資源已經用完,到達semaphore的SEM_NSEMS_MAX限制。
    -ENOSYS:系統不支援sem_init()函數。
    -EPERM:process缺少初始化semaphore所需的權限。
  • sem_post():增加semaphore值(加1)

    語法:
    int sem_post(sem_t *sem);

    #include
    sem_t sem;
    int rc;
    rc = sem_post(&sem);

    sem_post()成功完成後會回傳0,若回傳值為 -1則表示執行發生錯誤,如果出現下任一情況,該函數將失敗並回傳對應值:
    -EINVAL:未對應到有效的semaphore。
    -ENOSYS:系統不支援sem_post()函數。

  • sem_wait():減少semaphore值(減1)

    語法:
    int sem_wait(sem_t *sem);

    #include
    sem_t sem;
    int rc;
    rc = sem_wait(&sem);

    sem_wait()成功完成後會回傳0,若回傳值為 -1則表示執行發生錯誤,如果出現下任一情況,該函數將失敗並回傳對應值:
    -EINVAL:未對應到有效的semaphore。
    -ENOSYS:系統不支援sem_wait()函數。

  • sem_trywait():嘗試減少semaphore值(減1)

    語法:
    int sem_trywait(sem_t *sem);

    #include
    sem_t sem;
    int rc;
    rc = sem_trywait(&sem);

    sem_trywait()成功完成後會回傳0,若回傳值為 -1則表示執行發生錯誤,且不會block呼叫的thread,如果出現下任一情況,該函數將失敗並回傳對應值:
    -EINVAL:未對應到有效的semaphore。
    -ENOSYS:系統不支援sem_post()函數。
    -EINTR:此函數被semaphore中斷。
    -EAGAIN:semaphore值小於或等於0,無可用的semaphore。
  • sem_destroy():銷毀semaphore

    語法:
    int sem_destroy(sem_t *sem);

    #include
    sem_t sem;
    int rc;
    rc = sem_destroy(&sem);

    sem_destroy()成功完成後會回傳0,若回傳值為 -1則表示執行發生錯誤,如果出現下任一情況,該函數將失敗並回傳對應值:
    -EINVAL:未對應到有效的semaphore。
    -EBUSY:仍有process或thread被阻塞(blocked)在該semaphore。

二、範例程式

下列C範例程式可於不同系統計算SEM_VALUE_MAX的值。
/*semaphore.c*/
/*count SEM_VALUE_MAX*/
/*gcc -lpthread -lrt semaphore.c */

#include
#include
#include
#include

int main (int argc, char *argv[])
{
int value;
int rc = 0;
sem_t test_semaphore;
sem_init(&test_semaphore, 0, 1);
sem_getvalue(&test_semaphore, &value);
printf("The value of semaphore is %d\n", value);
while(rc == 0 & (value < 2147483647 & value > 0) )
{
rc = sem_post(&test_semaphore);
sem_getvalue(&test_semaphore, &value);
}

printf("sem_post returns %d\n", rc);
printf("The value of semaphore is %d\n", value);
rc = sem_post(&test_semaphore);
sem_getvalue(&test_semaphore, &value);
printf("sem_post returns %d\n", rc);
printf("The value of semaphore is %d\n", value);
}

參考文獻

http://compgroups.net/comp.unix.solaris/value-of-POSIX_SEM_VALUE_MAX
http://www.ibm.com/developerworks/cn/linux/l-ipc2lin2.html
http://www.cs.gmu.edu/~rcarver/ModernMultithreading/LectureNotes/Chapter3NotesPthreads.pdf
http://en.wikipedia.org/wiki/Semaphore_(programming)
http://www.5dlinux.com/article/6/2010/linux_38554.html
http://bugs.python.org/file12391/explore_sem_value_max.c



转载自:http://www.syscom.com.tw/ePaper_Content_EPArticledetail.aspx?id=213&EPID=176&j=5&HeaderName=%E6%8A%80%E8%A1%93%E5%88%86%E4%BA%AB

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Semaphore(信号量)是一种在多线程编程中用于控制访问共享资源的机制。它是由一个计数器和一组等待队列组成的数据结构,用于协调多个进程/线程对共享资源的访问。Semaphore维护了一个计数器,表示当前可用的资源数量,当某个进程/线程需要访问共享资源时,它会尝试获取一个信号量,如果信号量计数器大于0,则该进程/线程可以继续执行,同时信号量计数器减1;如果信号量计数器为0,则该进程/线程需要等待其他进程/线程释放资源,进入等待队列中。当某个进程/线程访问完共享资源后,它会释放信号量,使信号量计数器加1,并且唤醒等待队列中的一个进程/线程去访问共享资源。Semaphore可以用于解决多进程/线程间的同步问题,避免竞态条件和死锁问题的发生。 ### 回答2: Semaphore(信号量)是一种操作系统的同步机制,用于协调多个线程或进程之间的共享资源的访问。 Semaphore可以理解为一个计数器,表示可用资源的数量。具体而言,Semaphore包含两个基本操作P操作(等待)和V操作(发信号)。P操作用于申请资源,如果计数器大于0,则可以使用资源且计数器减1;如果计数器为0,则线程被阻塞。V操作用于释放资源,使计数器加1,并唤醒等待的线程。 Semaphore主要解决的问题是进程间的互斥和同步。通过Semaphore,我们可以限制对共享资源的访问,保证在同一时间只有有限数量的线程可以访问该资源,避免了数据不一致或竞争条件的发生。此外,Semaphore还可以用于线程间的通信,通过等待和发信号的机制,线程可以协调彼此的执行顺序。 Semaphore有两种类型:计数信号量和二信号量。计数信号量允许多个线程同时访问资源,计数器的初始可以是任意;而二信号量只允许一个线程访问资源,计数器的初始只能是0或1。 Semaphore操作系统中非常重要的同步机制,广泛应用于进程调度、线程池、内存管理等领域。合理使用Semaphore可以提高系统的效率和性能,确保共享资源的安全访问。但是,过多或不正确地使用Semaphore可能导致死锁或资源竞争的问题,因此在使用Semaphore时需要谨慎处理。 ### 回答3: Semaphore(信号量)是一种用于控制多线程或多进程并发访问临界资源的同步机制。它可以用于保证资源的互斥访问、线程的间隔执行以及解决生产者消费者问题等。 信号量的原理是通过一个由非负整数构成的计数器来控制对资源的访问。当计数器的大于等于0时,表示资源可用,线程可以访问该资源;当计数器的小于0时,表示资源不可用,线程需要等待。通过对信号量的加减操作来控制计数器的,从而控制对资源的访问。 信号量提供了两个主要操作:P(等待)和V(发送信号)。P操作用于申请资源,当信号量的计数器大于0时,计数器减1,线程可以访问资源;当计数器小于等于0时,线程需要等待。V操作用于释放资源,当信号量的计数器小于0时,计数器加1,唤醒等待的线程;当计数器大于等于0时,计数器不变。 信号量的应用非常广泛,例如实现互斥锁、线程池、资源池等。在实际开发中,我们可以根据需要创建一个信号量对象,并设置初始的计数器。通过调用P和V操作来控制对共享资源的访问,从而实现线程的同步与互斥。 需要注意的是,信号量的使用需要谨慎,错误的信号量操作可能导致死锁或资源竞争等问题。因此,在多线程编程中,合理地使用信号量,可以有效地提高程序的并发性能和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值