1. 程式人生 > >Linux訊號量 sem_t簡介

Linux訊號量 sem_t簡介

函式介紹

#include<semaphore.h>

訊號量的資料型別為結構sem_t,它本質上是一個長整型的數。

函式sem_init()用來初始化一個訊號量。它的原型為:int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));sem為指向訊號量結構的一個指標;pshared不為0時此訊號量在程序間共享,否則只能為當前程序的所有執行緒共享;value給出了訊號量的初始值。訊號量用sem_init函式建立的,下面是它的說明:
int sem_init (sem_t *sem, int pshared, unsigned int value); 這個函式的作用是對由sem指定的訊號量進行初始化,設定好它的共享選項,並指定一個整數型別的初始值。pshared引數控制著訊號量的型別。如果 pshared的值是0,就表示它是當前里程的區域性訊號量;否則,其它程序就能夠共享這個訊號量。我們現在只對不讓程序共享的訊號量感興趣。 (這個引數 受版本影響), pshared傳遞一個非零將會使函式呼叫失敗,屬於無名訊號量。  

sem_open功能:建立並初始化有名訊號燈,引數:name   訊號燈的外部名字(不能為空,為空會出現段錯誤)  oflag   選擇建立或開啟一個現有的訊號燈  mode 許可權位  value 訊號燈初始值  返回值:成功時返回指向訊號燈的指標,出錯時為SEM_FAILED,oflag引數能是0(開啟一個已建立的)、O_CREAT(建立一個訊號燈)或O_CREAT|O_EXCL(如果沒有指定的訊號燈就建立),如果指定了O_CREAT,那麼第三個和第四個引數是需要的;其中mode引數指定許可權位,value引數指定訊號燈的初始值,通常用來指定共享資源的書面。該初始不能超過 SEM_VALUE_MAX,這個常值必須低於為32767。二值訊號燈的初始值通常為1,計數訊號燈的初始值則往往大於1。

       如果指定了O_CREAT(而沒有指定O_EXCL),那麼只有所需的訊號燈尚未存在時才初始化他。所需訊號燈已存在條件下指定O_CREAT不是個錯誤。該標誌的意思僅僅是“如果所需訊號燈尚未存在,那就建立並初始化他”。不過所需訊號燈等已存在條件下指定O_CREAT|O_EXCL卻是個錯誤。sem_open返回指向sem_t訊號燈的指標,該結構裡記錄著當前共享資源的數目。

sem_close 關閉有名訊號燈。

若成功則返回0,否則返回-1。一個程序終止時,核心還對其上仍然開啟著的所有有名訊號燈自動執行這樣的訊號燈關閉操作。不論該程序是自願終止的還是非自願終止的,這種自動關閉都會發生。但應注意的是關閉一個訊號燈並沒有將他從系統中刪除。這就是說,Posix有名訊號燈至少是隨核心持續的:即使當前沒有程序開啟著某個訊號燈,他的值仍然保持。多程序開啟時候,一邊sem_close後,仍可以開啟已經開啟的訊號量。
sem_unlink

從系統中刪除訊號燈 定義:int sem_unlink(const char *name);若成功則返回0,否則返回-1。有名訊號燈使用sem_unlink從系統中刪除。每個訊號燈有一個引用計數器記錄當前的開啟次數,sem_unlink必須等待這個數為0時才能把name所指的訊號燈從檔案系統中刪除。也就是要等待最後一個sem_close發生。
sem_getvalue 測試訊號燈

函式sem_post( sem_t *sem )用來增加訊號量的值。當有執行緒阻塞在這個訊號量上時,呼叫這個函式會使其中的一個執行緒不在阻塞,選擇機制同樣是由執行緒的排程策略決定的。int sem_post(sem_t *sem);sem_post() 成功時返回 0;錯誤時,訊號量的值沒有更改,-1 被返回,並設定errno 來指明錯誤。錯誤   EINVAL  sem 不是一個有效的訊號量。  EOVERFLOW 訊號量允許的最大值將要被超過。

函式sem_wait( sem_t *sem )被用來阻塞當前執行緒直到訊號量sem的值大於0,解除阻塞後將sem的值減一,表明公共資源經使用後減少。

 這兩個函式控制著訊號量的值,它們的定義如下所示:
  #include <semaphore.h> int sem_wait(sem_t * sem);int sem_post(sem_t * sem);
        這兩個函式都要用一個由sem_init呼叫初始化的訊號量物件的指標做引數。
        sem_post函式的作用是給訊號量的值加上一個“1”,它是一個“原子操作”---即同時對同一個訊號量做加“1”操作的兩個執行緒是不會衝突的;而同 時對同一個檔案進行讀、加和寫操作的兩個程式就有可能會引起衝突。訊號量的值永遠會正確地加一個“2”--因為有兩個執行緒試圖改變它。
        sem_wait函式也是一個原子操作,它的作用是從訊號量的值減去一個“1”,但它永遠會先等待該訊號量為一個非零值才開始做減法。也就是說,如果你對 一個值為2的訊號量呼叫sem_wait(),執行緒將會繼續執行,介訊號量的值將減到1。如果對一個值為0的訊號量呼叫sem_wait(),這個函式就 會地等待直到有其它執行緒增加了這個值使它不再是0為止。如果有兩個執行緒都在sem_wait()中等待同一個訊號量變成非零值,那麼當它被第三個執行緒增加 一個“1”時,等待執行緒中只有一個能夠對訊號量做減法並繼續執行,另一個還將處於等待狀態。訊號量這種“只用一個函式就能原子化地測試和設定”的能力下正是它的價值所在。 還有另外一個訊號量函式sem_trywait,它是sem_wait的非阻塞搭檔。

函式sem_trywait ( sem_t *sem )是函式sem_wait()的非阻塞版本,它直接將訊號量sem的值減一。在成功完成之後會返回零。其他任何返回值都表示出現了錯誤。  

函式sem_destroy(sem_t *sem)用來釋放訊號量sem,屬於無名訊號量。 

    最後一個訊號量函式是sem_destroy。這個函式的作用是在我們用完訊號量對它進行清理。下面的定義:#include<semaphore.h>int sem_destroy (sem_t *sem);
這個函式也使用一個訊號量指標做引數,歸還自己戰勝的一切資源。在清理訊號量的時候如果還有執行緒在等待它,使用者就會收到一個錯誤。與其它的函式一樣,這些函式在成功時都返回“0”。

 無名訊號量的例子:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

sem_t bin_sem;
void *thread_function1(void *arg)
{
 printf("thread_function1--------------sem_wait\n");
 sem_wait(&bin_sem);
 printf("sem_wait\n");
 while (1)
 {
  printf("th1 running!\n");
  sleep(1);
 }
}

void *thread_function2(void *arg)
{
 printf("thread_function2--------------sem_post\n");
 sem_post(&bin_sem);
 printf("sem_post\n");
 while (1)
 {
  printf("th2 running!\n");
  sleep(1);
 }
}
int main()
{
 int res;
 pthread_t a_thread;
 void *thread_result;
 
 res = sem_init(&bin_sem, 0, 0);
 if (res != 0)
 {
  perror("Semaphore initialization failed");
 }
  printf("sem_init\n");
 res = pthread_create(&a_thread, NULL, thread_function1, NULL);
 if (res != 0)
 {
  perror("Thread creation failure");
 }
 printf("thread_function1\n");
 sleep(5);
 printf("sleep\n");
 res = pthread_create(&a_thread, NULL, thread_function2, NULL);
 if (res != 0)
 {
  perror("Thread creation failure");
 }
 while (1)
 {
   printf("running !\n");
   sleep(5);
 }
}

執行結果:
sem_init
thread_function1
thread_function1--------------sem_wait
sleep
thread_function2--------------sem_post
sem_wait
sem_post

有名訊號量在無相關程序間的同步

       有名訊號量的特點是把訊號量的值儲存在檔案中。這決定了它的用途非常廣:既可以用於執行緒,也可以用於相關程序間,甚至是不相關程序。由於有名訊號量的值是儲存在檔案中的,所以對於相關程序來說,子程序是繼承了父程序的檔案描述符,那麼子程序所繼承的檔案描述符所指向的檔案是和父程序一樣的,當然檔案裡面儲存的有名訊號量值就共享了。

       有名訊號量是位於共享記憶體區的,那麼它要保護的資源也必須是位於共享記憶體區,只有這樣才能被無相關的程序所共享。在下面這個例子中,服務程序和客戶程序都使用shmgetshmat來獲取得一塊共享記憶體資源。然後利用有名訊號量來對這塊共享記憶體資源進行互斥保護。

File1: server.c 
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SHMSZ 27
char SEM_NAME[]= "vik";

int main()
{
    char ch;
    int shmid;
    key_t key;
    char *shm,*s;
    sem_t *mutex;

    //name the shared memory segment
    key = 1000;

    //create & initialize semaphore
    mutex = sem_open(SEM_NAME,O_CREAT,0644,1);
    if(mutex == SEM_FAILED)
    {
      perror("unable to create semaphore");
      sem_unlink(SEM_NAME);
      exit(-1);
    }

    //create the shared memory segment with this key
    shmid = shmget(key,SHMSZ,IPC_CREAT|0666);
    if(shmid<0)
{
        perror("failure in shmget");
        exit(-1);
}

    //attach this segment to virtual memory
    shm = shmat(shmid,NULL,0);

    //start writing into memory
    s = shm;
    for(ch='A';ch<='Z';ch++)
    {
        sem_wait(mutex);
        *s++ = ch;
        sem_post(mutex);
     }

    //the below loop could be replaced by binary semaphore
    while(*shm != '*')
    {
        sleep(1);
}
    sem_close(mutex);
    sem_unlink(SEM_NAME);
    shmctl(shmid, IPC_RMID, 0);
    exit(0);
}

File 2: client.c
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SHMSZ 27
char SEM_NAME[]= "vik";

int main()
{
    char ch;
    int shmid;
    key_t key;
    char *shm,*s;
    sem_t *mutex;

    //name the shared memory segment
    key = 1000;

    //create & initialize existing semaphore
    mutex = sem_open(SEM_NAME,0,0644,0);
    if(mutex == SEM_FAILED)
    {
        perror("reader:unable to execute semaphore");
        sem_close(mutex);
        exit(-1);
    }

    //create the shared memory segment with this key
    shmid = shmget(key,SHMSZ,0666);
    if(shmid<0)
    {
        perror("reader:failure in shmget");
        exit(-1);
    }

    //attach this segment to virtual memory
    shm = shmat(shmid,NULL,0);

    //start reading
    s = shm;
    for(s=shm;*s!=NULL;s++)
    {
        sem_wait(mutex);
        putchar(*s);
      sem_post(mutex);
    }

  //once done signal exiting of reader:This can be replaced by another semaphore
    *shm = '*';
    sem_close(mutex);
    shmctl(shmid, IPC_RMID, 0);
    exit(0);
}


...

相關推薦

Linux訊號 sem_t簡介

函式介紹 #include<semaphore.h> 訊號量的資料型別為結構sem_t,它本質上是一個長整型的數。 函式sem_init()用來初始化一個訊號量。它的原型為:int sem_init __P ((sem_t *__sem, int __pshared, unsigned int

Linux訊號sem_t簡單例項運用

sem_t sem;  定義一個訊號量變數。使用時需首先使用sem_init()函式初始化。  在多執行緒程式設計中,想讓某個執行緒阻塞等待,減少cpu佔用,在該需要執行時才執行。使用訊號量一個A執行緒sem_wait(),阻塞等待;一個B執行緒在需要執行A執行緒時sem_p

linux中訊息佇列kfifo和訊號sem_t的用法

使用kfifo和sem_t配合來實現訊息佇列:由sem來管理目前可以傳送和接收的總的訊息數,由kfifo來儲存訊息。具體實現起來就是定義訊號量sem_t_send和sem_t_recv,sem_t_send設為max_num,sem_t_recv設為0。

Linux訊號sem_t封裝成事件物件

    將訊號量sem_t相關的一組API封裝成Win32平臺上的事件物件類之後,在Linux平臺上就可以像使用事件物件那樣,方便地進行執行緒同步了。 class CEventImpl { protected: /* 建立匿名訊號量 `bAutoReset

關於Linux訊號的理解和探討(別說看不懂,耐心看完,你會恍然大悟~)

工作環境(藍色粗體字為特別注意內容) 1,實驗環境:Linux2.6 2,參考文獻:https://www.cnblogs.com/LZYY/p/3453582.html 最近在操作裝置檔案的時候,要求使用獨佔模式使用串列埠裝置,即一個程序用完之後釋放該串列埠,供其他程序使用。該如何實現該

訊號sem_t,互斥鎖pthread_mutex_t的使用

訊號量的資料型別為結構sem_t,它本質上是一個長整型的數。函式sem_init()用來初始化一個訊號量。它的原型為:   extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __val

linux--訊號

訊號量 什麼是訊號量? 訊號量是程序間通訊方式之一,用於實現程序間的同步與互斥。 同步與互斥 同步:保證對臨界資源訪問的時序可控性,兩個或兩個以上的程序或執行緒在執行過程中協同步調,按預定的先後次序執行. 比如只有超市進貨之後我才能去消費。 互斥:保證同一時間

linux訊號

Linux程序間的通訊方式和原理程序的概念程序是作業系統的概念,每當我們執行一個程式時,對於作業系統來講就建立了一個程序,在這個過程中,伴隨著資源的分配和釋放。可以認為程序是一個程式的一次執行過程。程序通訊的概念程序使用者空間是相互獨立的,一般而言是不能相互訪問的。但很多情況

linux訊號程式設計semget、semop

訊號量(訊號燈)與其他程序間訪問方式不同,它的用途主要是保護臨界資源。程序可以根據訊號量來判斷能否訪問某些共享資源,實際上它是一個整數,訊號量還可以用於程序的同步。 訊號量分為: 1、二值訊號燈:訊號燈只有0和1兩個值,類似互斥鎖。當兩者有不同:訊號燈強調共享資源,只要共享資源可用,其他程序同樣可

linux 訊號實現互斥操作

本次程式實現了通過訊號量來實現父程序與子程序互斥操作,當父程序執行列印操作時子程序被阻塞,當子程序執行列印操作時父程序阻塞。實現程式碼如下:#include <stdio.h> #include <unistd.h> #include <stdl

訊號 sem_t

訊號量是在多執行緒環境中共享資源的計數器。對訊號量的基本操作無非有三個:對訊號量的增加;然後阻塞執行緒等待,直到訊號量不為空才返回;然後就是對訊號量的減少。    在程式設計中,訊號量最常用的方式就是一個執行緒A使用sem_wait阻塞,因為此時訊號量計數為0,直到另外一個

Linux 訊號同步實驗

題目:有一個盤子,父親放入蘋果,母親放入桔子,女兒取出蘋果,兒子取出桔子。 同步關係:父親放蘋果和女兒取蘋果 && 母親放桔子和兒子取桔子 互斥關係:父親放蘋果和母親放桔子 下面是原始碼: #include <stdio.h> #include

【ARM&LinuxLinux訊號互斥程式設計

《訊號量互斥程式設計示例演示》 /**************************************************************************************** * 檔名: a_pro.c * 建立者:

Linux多執行緒程式設計---執行緒間同步(互斥鎖、條件變數、訊號和讀寫鎖)

本篇博文轉自http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/ Linux下提供了多種方式來處理執行緒同步,最常用的是互斥鎖、條件變數、訊號量和讀寫鎖。  下面是思維導

linux 多執行緒之訊號 sem_init

1. 什麼是訊號量 linux sem 訊號量是一種特殊的變數,訪問具有原子性, 用於解決程序或執行緒間共享資源引發的同步問題。 使用者態程序對 sem 訊號量可以有以下兩種操作: 等待訊號量 當訊號量值為 0 時,程式等待;當訊號量值大於 0 時,訊號量減 1,程式

Linux基礎(四)——訊號與PV操作

在計算機作業系統中,PV操作是程序管理中的難點。1、基本含義      什麼是訊號量?訊號量(semaphore)的資料結構為一個值和一個指標,指標指向等待該訊號量的下一個程序。訊號量的值與相應資源的使用情況有關。當它的值大於0時,表示當前可用資源的

Linux:程序間通訊(匿名管道命名管道)(共享記憶體,訊息佇列,訊號

目錄 程序間通訊的介紹 管道 匿名管道 原理: 程式碼實現 匿名管道特性 實現管道符 |  命名管道 命名管道特性 程式碼實現 管道讀寫規則 作業系統中ipc的相關命令 共享記憶體(重點) 生命週期: 程式碼實現 程式碼實現獲

linux核心態和使用者態的訊號

在Linux的核心態和使用者態都有訊號量,使用也不同,簡單記錄一下。 1> 核心訊號量,由核心控制路徑使用。 核心訊號量是struct semaphore型別的物件,它在<asm/semaphore.h>中定義 struct semaphore {    

Linux c++,用訊號實現消費者生產者佇列(程式碼可直接通過編譯)

//用訊號量實現的一個消費者生產者佇列, #include <iostream> #include <pthread.h> #include <semaphore.h> #include <errno.h> #include <queue>

c-linux-IPC-訊號semaphore-學習

###概念### 場景:某個執行緒(程序)能從訊號拿到鎖,則執行,否則阻塞等待。 訊號量:可以理解為訊號集中某個訊號當前鎖的數值                  正值:尚可接受的程序數