1. 程式人生 > >System V訊號量-semget()、semop()和semctl()

System V訊號量-semget()、semop()和semctl()

簡單介紹

這是我開這個欄目的第一篇文章,順序也不是按照《Unix網路程式設計》(以下簡稱網編)的章節順序往下寫的,可能文章會提及一些前面章節的概念,遇到的話,我會做一些引導,讀者也可以自己找找相關的內容或書籍檢視。
訊號量是一種用於提供不同程序間或一個給定程序的不同執行緒間同步手段的原語。我們討論的訊號量一般都包括二值訊號量和計數訊號量,而提及System V訊號量時指的是計數訊號量集,但是提及Poix 訊號量指的就是單個的計數訊號量。
對於系統中每一個訊號量集,核心維護了一個如下的資訊結構,定義在 sys/sem.h 標頭檔案中,

struct semid_ds {
    struct ipc_perm sem_perm;           /*  operation permission struct */
    struct sem *sem_base;               /*  ptr to
array of semaphores in set */ ushort sem_nsems; /* number of sems in set */ time_t sem_otime; /* last operation time (semop)*/ time_t sem_ctime; /* time of creation or last IPC_SET */ };

其中,ipc_perm含有當前這個訊號量的訪問許可權(參考網編3.3節);
sem結構是核心用於維護某個給定訊號量的一組值的資料結構,需要注意的是sem_base是指向sem結構陣列的指標,當前訊號量集中的每一個訊號量對應其中的一個數組元素,結構如下:

struct sem {
    unsigned short  semval;     /* semaphore value */
    pid_t       sempid;         /* pid of last operation */
    unsigned short  semncnt;    /* # awaiting semval > cval */
    unsigned short  semzcnt;    /* # awaiting semval == 0 */
};

我們假定訊號量集中有兩個訊號量,該訊號量集可以如下圖表示:
這裡寫圖片描述
注:更詳細的資訊大家可以參考《Unix網路程式設計》

函式介紹

System V 訊號量涉及到的函式有:semget()semctl()semop(),下面我會一一介紹這幾個函式的使用。

semget()

#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
//返回:若成功則返回一個稱為訊號量識別符號的整數,semop和semctl函式
//都將使用它;失敗返回-1

功能:建立一個訊號量集或者開啟一個已存在的訊號量集;
引數:
key 是一個key_t型別的整數,我們通常使用ftok函式將一個已存在的路徑和一個整數識別符號轉換成一個key_t值,稱為IPC鍵(網編P27);
nsems:訊號量集中訊號量的個數,如果是開啟一個訊號量集,nsems可以設定成0,訊號量集建立完成之後,我們不能改變其中的訊號量個數;
semflg:設定改訊號量集的訪問許可權(網編3.4、3.5節),該引數的讀寫許可權位存入sem_perm.mode;

struct ipc_perm
{
         uid_t           uid;            /* [XSI] Owner's user ID */
         gid_t           gid;            /* [XSI] Owner's group ID */
         uid_t           cuid;           /* [XSI] Creator's user ID */
         gid_t           cgid;           /* [XSI] Creator's group ID */
         mode_t          mode;           /* [XSI] Read/write permission */
         unsigned short  _seq;           /* Reserved for internal use */
         key_t           _key;           /* Reserved for internal use */
};

我們來建立一個訊號量:

key = ftok(".",'s');
/**
 * 建立一個訊號量
 */
int sem_create(key_t key){
    int semid;
    semid = semget(key,1,IPC_CREAT | 0666);  //1 訊號量集中只有一個訊號量,semflg還可以或上 IPC_EXCL 表示建立成功之後再次建立會失敗
    if (semid == -1){
        ERR_EXIT("semget");
    }
    return semid;
}

先看下有沒有訊號量集:
這裡寫圖片描述
執行程式:
這裡寫圖片描述
如果加上 IPC_EXCL,再次編譯執行程式:
這裡寫圖片描述
我們看到,程式直接報錯了。
我們再寫一個開啟訊號量集的函式:

/**
 * 開啟一個訊號量
 */
int sem_open(key_t key){
    int sem_id;
    sem_id = semget(key,0,0);
    if(-1 == sem_id){
        ERR_EXIT("semget");
    }
    return sem_id;
}

當實際建立一個新的訊號量集時,相應的semid_ds結構的以下成員將被初始化:
1、sem_perm結構中的uid和cuid被設定成呼叫程序的有效使用者id,gid和guid被設定成呼叫程序的有效組id;
2、semflg引數的讀寫許可權位存入sem_perm.mode;
3、sem_otime被置為0,sem_ctime被置為當前時間;
4、sem_nsems被置為nests引數的值;
需要注意的是,與該集合中每個訊號量關聯的sem結構並不初始化,需要呼叫semctl函式進行初始化;

semctl()

#include <sys/sem.h>
int semctl(int semid, int semnum, int cmd, .../* union semun arg */);
//成功返回非負值,失敗返回-1

功能:對一個訊號量執行各種控制操作;
引數:
semid:待操作的訊號量集,即由semget返回的訊號量集識別符號;
semnum: 標識訊號量集中的某一個成員(0、1…知道nsems-1);
cmd:將對訊號量執行的操作(如下);
第四個引數是可選的,取決於cmd;

union semun {
    int     val;                /* value for SETVAL */
    struct semid_ds *buf;       /* buffer for IPC_STAT & IPC_SET */
    unsigned short  *array;     /* array for GETALL & SETALL */
};

GETVAL:把semval的當前值作為函式的返回值返回;
SETVAL:把semval的值設定成arg.val;
GETALL:返回訊號量集中每一個成員的semval的值,這些值通過arg.array指標返回;
SETALL:設定訊號量集中每一個訊號量的semval的值,這些值通過arg.array指標指定;
IPC_RMID:把由semid指定的訊號量集從系統中刪除;
IPC_SET:設定指定訊號量集中的semid_ds結構中的以下三位成員:sem_perm.uid、sem_perm.gid和sem_perm.mode,這些值來自由arg.buf引數指向的結構中的相應成員;
IPC_STAT:通過arg.buf引數返回指定訊號量集中的semid_ds結構;
現在,我們對訊號量集能做的操作更多了,例如:設定一個訊號量的值、獲取一個訊號量的值或者刪除一個訊號量集。

// 設定一個訊號量的值
int sem_setval(int semid,int val){
    union semun su;
    su.val = val;
    int ret;
    ret = semctl(semid,0,SETVAL,su);
    if(-1 == ret){
        ERR_EXIT("sem_setval");
    }
    return 0;
}
// 獲取一個訊號量的值
int sem_getval(int semid){
    int ret;
    ret = semctl(semid,0,GETVAL,0);
    if (-1 == ret){
        ERR_EXIT("sem_getval");
    }
    printf("current val is:%d\n",ret);
    return 0;
}
// 刪除一個訊號量集
int sem_d(int semid){
    int ret;
    ret = semctl(semid,0,IPC_RMID,0);
    if(-1 == ret){
        ERR_EXIT("sem_d");
    }
    return 0;
}

相關推薦

System V訊號-semget()semop()semctl()

簡單介紹 這是我開這個欄目的第一篇文章,順序也不是按照《Unix網路程式設計》(以下簡稱網編)的章節順序往下寫的,可能文章會提及一些前面章節的概念,遇到的話,我會做一些引導,讀者也可以自己找找相關的內容或書籍檢視。 訊號量是一種用於提供不同程序間或一個給定程

Linux程序間通訊:訊號 semget()semop()semctl()

這篇文章將講述別一種程序間通訊的機制——訊號量。注意請不要把它與之前所說的訊號混淆起來,訊號與訊號量是不同的兩種事物。有關訊號的更多內容,可以閱讀我的另一篇文章:Linux程序間通訊 -- 訊號。下面就進入訊號量的講解。 一、什麼是訊號量 為了防止出現

linux下c程式設計之訊號semgetsemopsemctl函式

訊號量 今天去參加北京市的植樹志願者活動啦!早上起來的挺早的,6:10就被傑子給叫起來啦,帶著對春天的嚮往,我們坐著不花錢的大巴去做為市領導服務去啦!發了一個小紅帽還有一個紅色的制服。 唉。。。說好

Linux程序間通訊(IPC)程式設計實踐(十)System V訊號---PV操作經典題目

//P原語     //P(semaphore *S)     wait(semaphore *S)       {           -- S->value;           if (S->value < 0)           {   

System V 訊號(三)之用訊號解決哲學家進餐問題

一.哲學家就餐問題           5個哲學家,5個筷子。5個哲學家圍坐在一張桌子上,筷子放在分別放在每個哲學家的兩旁。如果所有哲學家在某個時刻同時拿起左邊的筷子,那麼右邊的筷子就都被其他的哲學家拿了,造成大家都無法吃飯。但是大家都不想放下左邊的筷子(規則是先拿起左邊

System V 訊號

 訊號量概念: 1.二值訊號量:值為0或者1。若互斥鎖就是這種 2.計數訊號量:值為0~N之間的訊號量 3.計數訊號量集:就是一個或多個訊號量構成一個集合 System V訊號量就是計數訊號量集,而Posix訊號量則是單個計數訊號量 ==================

System V訊號

目錄 1. System V IPC 概述 IPC鍵和ftok函式 ipc_perm結構 建立與開啟IPC物件 ipcs和ipcrm命令 2.

Linux中的System V訊號

> 在程序同步,併發執行時,保證按序地訪問共享資源是十分重要的。因此引入了臨界區的概念,一次只能有一個執行緒進入臨界區完成他的指令。而訊號量(semaphore)的作用,類似於一個交通訊號燈,它負責程序協作,因此訊號量又稱為訊號燈。 在Linux系統中,它提供兩種訊號量: - **核心訊號量**,由核心控

linux訊號程式設計semgetsemop

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

訊號函式(semgetsemopsemctl

函式呼叫為semctl(),semget(),semop()等函式。 ---------------------------------------------------------我是分割線-------------------------------------------------------- 訊

linux程序控制之訊號 semgetsemctlsemop

轉載自 https://www.cnblogs.com/52php/p/5851570.html 這篇文章將講述別一種程序間通訊的機制——訊號量。注意請不要把它與之前所說的訊號混淆起來,訊號與訊號量是不同的兩種事物。有關訊號的更多內容,可以閱讀我的另一篇文章:L

Linux程序間通訊之訊號(semaphore)訊息佇列(Message Queue)共享記憶體(Share Memory)

System V 程序通訊方式:訊號量(semaphore)、訊息佇列(Message Queue)和共享記憶體(Share Memory) 訊號量 訊號量(semaphore)實際是一個整數,它的值由多個程序進行測試(test)和設定(set)。就每個程序所關心的測試和

訊號:整型記錄型訊號以及利用訊號實現程序互斥前驅關係

訊號量機構是一種功能較強的機制,可用來解決互斥與同步的問題,它只能被兩個標準的原語wait(S)和signal(S)來訪問,也可以記為“P操作”和“V操作”。原語是指完成某種功能且不被分割不被中斷執行的操作序列,通常可由硬體來實現完成不被分割執行特性的功能。如前述的“Tes

程序(三):程序同步——Lock(鎖)Semaphore(訊號Event(事件)

目錄 鎖 —— multiprocess.Lock 訊號量 —— multiprocess.Semaphore(瞭解) 事件 —— multiprocess.Event(瞭解) 鎖 —— multiprocess.Lock   當多個程序使用同一份資料資源的時候,就會引發資料

執行緒(三):Lock(互斥鎖)RLock( 遞迴鎖)Semaphore(訊號Event(事件)Condition(條件)Timer(定時器)queue(佇列)

目錄 一、鎖 1)同步鎖 2)死鎖與遞迴鎖 二、訊號量 三、事件 四、條件 五、定時器 六、執行緒佇列 一、鎖 1)同步鎖 #同步鎖的引用 from threading import Thread,Lock import os,time def wor

Java併發包之閉鎖/柵欄/訊號及併發模型

threadLocal能夠為每一個執行緒維護變數副本,常用於在多執行緒中用空間換時間     程序死鎖:程序死鎖,指多個程序迴圈等待他方佔有的資源而一直等待下去的局面;  程序活鎖:執行緒1,2需要同時佔有a,b才可以,1佔有a,2佔有b,為了避免死鎖,

作業系統(2.3程序同步)本章最後結合記錄型訊號的使用方法例題進行了詳細講解。

最近在準備推免的面試把王道的程序這一章拿出來做了一下,收穫挺多的,寫個文章總結下  2.3程序同步 訪問臨界資源過程 do{ entry section;//進入區 設定訪問臨界區標誌 critical section;//臨界區 訪問臨界資源 exit se

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

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

自旋鎖互斥體訊號

自旋鎖 Linux核心中最常見的鎖是自旋鎖(spin lock)。自旋鎖最多隻能被一個可執行執行緒持有。如果一個執行執行緒試圖獲得一個被已經持有的自旋鎖,那麼該執行緒就會一直進行忙迴圈——旋轉——等待鎖重新可用。要是鎖未被爭用,請求鎖的執行執行緒便能立刻得到它,繼續執行。在任意時間,自旋鎖都

訊號互斥鎖讀寫鎖條件變數之間的區別

訊號量 強調的是執行緒(或程序)間的同步:“訊號量用在多執行緒多工同步的,一個執行緒完成了某一個動作就通過訊號量告訴別的執行緒,別的執行緒再進行某些動作(大家都在sem_wait的時候,就阻塞在那裡)。當訊號量為單值訊號量是,也可以完成一個資源的互斥訪問。 有名