久久婷婷香蕉热狠狠综合,精品无码国产自产拍在线观看蜜,寡妇房东在做爰3,中文字幕日本人妻久久久免费,国产成人精品三上悠亚久久


linux下的信號量

分享(xiang)到:
           

    本文關鍵字: linux下的信號量,信號量編程

    一、信號量概述

    在多任(ren)務操作(zuo)系統環境下,多個進(jin)(jin)程(cheng)(cheng)會同時運(yun)行,并且一些進(jin)(jin)程(cheng)(cheng)間可能存在一定(ding)的關(guan)聯。多個進(jin)(jin)程(cheng)(cheng)可能為了(le)完成同一個任(ren)務相互協作(zuo),這就形成了(le)進(jin)(jin)程(cheng)(cheng)間的同步(bu)關(guan)系。而且在不(bu)同進(jin)(jin)程(cheng)(cheng)間,為了(le)爭奪(duo)有限的系統資源(yuan)(硬件或軟件資源(yuan))會進(jin)(jin)入競爭狀(zhuang)態,這就是進(jin)(jin)程(cheng)(cheng)間的互斥(chi)關(guan)系。

    進程間的互(hu)斥關系與同步(bu)關系存在(zai)的根源(yuan)(yuan)在(zai)于臨(lin)界(jie)(jie)資(zi)(zi)源(yuan)(yuan)。臨(lin)界(jie)(jie)資(zi)(zi)源(yuan)(yuan)是在(zai)同一(yi)個(ge)(ge)時(shi)刻只允許有限(xian)個(ge)(ge)(通常只有一(yi)個(ge)(ge))進程可以訪問(wen)(讀)或修改(寫(xie))的資(zi)(zi)源(yuan)(yuan),通常包括硬(ying)件(jian)資(zi)(zi)源(yuan)(yuan)(處理器、內存、存儲(chu)器及(ji)其(qi)他外圍設備等(deng))和軟件(jian)資(zi)(zi)源(yuan)(yuan)(共(gong)享(xiang)代碼(ma)(ma)段、共(gong)享(xiang)結構和變量等(deng))。訪問(wen)臨(lin)界(jie)(jie)資(zi)(zi)源(yuan)(yuan)的代碼(ma)(ma)叫(jiao)做臨(lin)界(jie)(jie)區,臨(lin)界(jie)(jie)區本身也會(hui)成(cheng)為臨(lin)界(jie)(jie)資(zi)(zi)源(yuan)(yuan)。

    信(xin)號量是用來解決進(jin)程間的(de)同步與互斥問題的(de)一(yi)種進(jin)程間通(tong)信(xin)機制,包括一(yi)個稱為信(xin)號量的(de)變量和(he)在該(gai)信(xin)號量下等(deng)待(dai)資(zi)(zi)源的(de)進(jin)程等(deng)待(dai)隊(dui)列(lie),以(yi)及對(dui)信(xin)號量進(jin)行的(de)兩個原(yuan)子操作(zuo)(PV操作(zuo))。其中(zhong)信(xin)號量對(dui)應于某一(yi)種資(zi)(zi)源,取一(yi)個非(fei)負(fu)的(de)整(zheng)型(xing)值(zhi)。信(xin)號量值(zhi)指的(de)是當前(qian)可(ke)用的(de)該(gai)資(zi)(zi)源的(de)數量,若等(deng)于0則(ze)意(yi)味著目(mu)前(qian)沒有可(ke)用的(de)資(zi)(zi)源。

    PV原子操作的具體定義(yi)如下。

    ● P操作:如果(guo)有(you)(you)可用的資(zi)源(yuan)(信號(hao)量值(zhi)>0),則(ze)占用一個資(zi)源(yuan)(給信號(hao)量值(zhi)減1,進(jin)(jin)入臨(lin)界(jie)區代碼);如果(guo)沒有(you)(you)可用的資(zi)源(yuan)(信號(hao)量值(zhi)=0),則(ze)被阻塞直(zhi)(zhi)到(dao)系(xi)統將(jiang)資(zi)源(yuan)分配給該進(jin)(jin)程(進(jin)(jin)入等待隊(dui)列,一直(zhi)(zhi)等到(dao)資(zi)源(yuan)輪到(dao)該進(jin)(jin)程)。

    ● V操作:如果在該(gai)信(xin)號(hao)量的(de)等(deng)待隊列中有(you)進程(cheng)在等(deng)待資(zi)源(yuan),則喚醒一(yi)個阻塞進程(cheng);如果沒有(you)進程(cheng)等(deng)待它,則釋放一(yi)個資(zi)源(yuan)(給信(xin)號(hao)量值加1)。

    常見的使用信號量(liang)訪問臨界區的偽(wei)代碼如下(xia):

    {
        /* 設R為某種資源,S為資源R的信號量 */
        INIT_VAL(S); /* 對信號量S進行初始化 */
        非臨界區;
        P(S); /* 進行P操作 */
        臨界區(使用資源R); /* 只有有限個(通常只有一個)進程被允許進入該區 */
        V(S); /* 進行V操作 */
        非臨界區;
    }

    簡(jian)單的信(xin)號(hao)量(liang)只(zhi)能取(qu)0和(he)1兩種(zhong)值,這種(zhong)信(xin)號(hao)量(liang)叫做二維(wei)(wei)信(xin)號(hao)量(liang)。在本節中(zhong),主要討論二維(wei)(wei)信(xin)號(hao)量(liang)。二維(wei)(wei)信(xin)號(hao)量(liang)的應用比較容(rong)易擴展到使用多維(wei)(wei)信(xin)號(hao)量(liang)的情(qing)況(kuang)。

    二、信號量編程

    1.函數說(shuo)明

    在Linux系統中,使用信號(hao)量(liang)通常分(fen)為以(yi)下幾個步(bu)驟(zou):

    (1)創建信(xin)(xin)號(hao)(hao)量或獲得在(zai)系(xi)統(tong)中已(yi)存在(zai)的信(xin)(xin)號(hao)(hao)量,此(ci)時需要調用(yong)semget()函數(shu)。不同(tong)進程(cheng)通(tong)過(guo)使用(yong)同(tong)一個信(xin)(xin)號(hao)(hao)量鍵(jian)值來獲得同(tong)一個信(xin)(xin)號(hao)(hao)量。

    (2)初始(shi)化信(xin)(xin)號量,此時使用semctl()函數(shu)的SETVAL操作。當(dang)使用二維信(xin)(xin)號量時,通常(chang)將信(xin)(xin)號量初始(shi)化為1。

    (3)進行信號量的(de)PV操作,此(ci)時調(diao)用semop()函數(shu)。這一步是實現進程間(jian)的(de)同步和互斥(chi)的(de)核(he)心工作部分。

    (4)如果不需要信(xin)號量,則從(cong)系統中刪(shan)除(chu)它,此時使用(yong)semctl ()函數的(de)(de)IPC_RMID操作(zuo)(zuo)。需要注意的(de)(de)是,在程序中不應該出現對已經(jing)被刪(shan)除(chu)的(de)(de)信(xin)號量的(de)(de)操作(zuo)(zuo)。

    2.函數格(ge)式

    ;表1列舉了semget()函(han)數的語法要(yao)點。

表(biao)1 semget()函數語法要點(dian)

所需頭文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函數原型 int semget(key_t key, int nsems, int semflg)
函數傳入值 key:信號量的鍵值,多個進程可以通過它訪問同一個信號量,其中有個特殊值IPC_PRIVATE,用于創建當前進程的私有信號量
nsems:需要創建的信號量數目,通常取值為1
semflg:同open()函數的權限位,也可以用八進制表示法,其中使用IPC_CREAT標志創建新的信號量,即使該信號量已經存在(具有同一個鍵值的信號量已在系統中存在),也不會出錯。如果同時使用IPC_EXCL標志可以創建一個新的唯一的信號量,此時如果該信號量已經存在,該函數會返回出錯
函數返回值 成功:信號量標識符,在信號量的其他函數中都會使用該值
出錯:-1

    表2列舉了semctl()函數的語法要點。

表2 semctl()函數語法要點

所需頭文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函數原型 int semctl(int semid, int semnum, int cmd, union semun arg)
函數傳入值 semid:semget()函數返回的信號量標識符
semnum:信號量編號,當使用信號量集時才會被用到。通常取值為0,就是使用單個信號量(也是第一個信號量)
cmd:指定對信號量的各種操作,當使用單個信號量(而不是信號量集)時,常用的操作有以下幾種。
● IPC_STAT:獲得該信號量(或者信號量集)的semid_ds結構,并存放在由第4個參數arg結構變量的buf域指向的semid_ds結構中。semid_ds是在系統中描述信號量的數據結構
● IPC_SETVAL:將信號量值設置為arg的val值
● IPC_GETVAL:返回信號量的當前值
● IPC_RMID:從系統中刪除信號量(或者信號量集)
arg:是union semnn結構,可能在某些系統中不給出該結構的定義,此時必須由程序員自己定義
     union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    }
函數返回值 成功:根據cmd值的不同而返回不同的值
IPC_STAT、IPC_SETVAL、IPC_RMID:返回0
IPC_GETVAL:返回信號量的當前值
出錯:-1

   &nbsp;表3列舉了(le)semop()函(han)數的語法要點。

表3 semop()函(han)數語法要點

所需頭文件 #include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函數原型 int semop(int semid, struct sembuf *sops, size_t nsops)
函數傳入值 semid:semget()函數返回的信號量標識符
sops:指向信號量操作數組,一個數組包括以下成員。
  struct sembuf
  {
    short sem_num; /* 信號量編號,使用單個信號量時,通常取值為0 */
    short sem_op;
    /* 信號量操作:取值為-1則表示P操作,取值為+1則表示V操作 */
    short sem_flg;
    /* 通常設置為SEM_UNDO。這樣在進程沒釋放信號量而退出時,系統自動釋放該進程中未
    釋放的信號量 */
  }
nsops:操作數組sops中的操作個數(元素數目),通常取值為1(一個操作)
函數返回值 成功:信號量標識符,在信號量的其他函數中都會使用該值
出錯:-1

    因為信號量(liang)相關(guan)的(de)函(han)(han)數(shu)(shu)調用(yong)接口比(bi)較復雜(za),我們可(ke)以(yi)將它們封裝成(cheng)二維單個信號量(liang)的(de)幾個基本函(han)(han)數(shu)(shu),分別(bie)為信號量(liang)初始(shi)化函(han)(han)數(shu)(shu)(或者信號量(liang)賦值函(han)(han)數(shu)(shu))init_sem()、P操作(zuo)函(han)(han)數(shu)(shu)sem_p()、V操作(zuo)函(han)(han)數(shu)(shu)sem_v()及(ji)刪除信號量(liang)函(han)(han)數(shu)(shu)del_sem()等,具體(ti)實現(xian)如下(xia):

    /* sem_com.c */
    #include "sem_com.h"
    /* 信號量初始化(賦值)函數 */
    int init_sem(int sem_id, int init_value)
    {
        union semun sem_union;
        sem_union.val = init_value;    /* init_value為初始值 */
        if (semctl(sem_id, 0, SETVAL, sem_union) == -1)
        {
            perror("Initialize semaphore");
            return -1;
        }
        return 0;
    }
    /* 從系統中刪除信號量的函數 */
    int del_sem(int sem_id)
    {
        union semun sem_union;
        if (semctl(sem_id, 0, IPC_RMID, sem_union) == -1)
        {
            perror("Delete semaphore");
            return -1;
        }
    }
    /* P操作函數 */
    int sem_p(int sem_id)
    {
        struct sembuf sem_b;
        sem_b.sem_num = 0;          /* 單個信號量的編號應該為0 */
        sem_b.sem_op = -1;          /* 表示P操作 */
        sem_b.sem_flg = SEM_UNDO;   /* 系統自動釋放將會在系統中殘留的信號量 */
        if (semop(sem_id, &sem_b, 1) == -1)
        {
            perror("P operation");
            return -1;
        }
        return 0;
    }
    /* V操作函數 */
    int sem_v(int sem_id)
    {
        struct sembuf sem_b;
        sem_b.sem_num = 0;           /* 單個信號量的編號應該為0 */
        sem_b.sem_op = 1;            /* 表示V操作 */
        sem_b.sem_flg = SEM_UNDO;    /* 系統自動釋放將會在系統中殘留的信號量 */
        if (semop(sem_id, &sem_b, 1) == -1)
        {
            perror("V operation");
            return -1;
        }
        return 0;
    }

    以(yi)下實(shi)例(li)說明了信號(hao)量(liang)的概念及基本用法。在實(shi)例(li)程序(xu)中,首先創(chuang)建一個子進程,然后(hou)使用信號(hao)量(liang)來控制(zhi)兩個進程(父子進程)間的執行順序(xu)。

    /* fork.c */
    #include <sys/types.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #define DELAY_TIME 3 /* 為了突出演示效果,等待幾秒 */

    int main(void)
    {
        pid_t result;
        int sem_id;

        sem_id = semget(ftok(".", 'a'), 1, 0666|IPC_CREAT); /* 創建一個信號量 */
        init_sem(sem_id, 0);

        /* 調用fork()函數 */
        result = fork();
        if(result == -1)
        {
            perror("Fork\n");
        }
        else if (result == 0) /* 返回值為0代表子進程 */
        {
            printf("Child process will wait for some seconds...\n");
            sleep(DELAY_TIME);
            printf("The returned value is %d in the child process(PID = %d)\n",
            result, getpid());
            sem_v(sem_id);
        }
        else /* 返回值大于0代表父進程 */
        {
            sem_p(sem_id);
            printf("The returned value is %d in the father process(PID = %d)\n",
            result, getpid());
            sem_v(sem_id);
            del_sem(sem_id);
        }
        exit(0);
    }

    讀者可以先從該程序(xu)中(zhong)刪除信號量相關的代(dai)碼部(bu)分(fen)并觀(guan)察運(yun)行結果。

    $ ./simple_fork
    Child process will wait for some seconds… /* 子進程在運行中 */
    /* 父進程先結束 */
    The returned value is 4185 in the father process(PID = 4184)
    /* 子進程后結束 */
  &nbsp; […]$ The returned value is 0 in the child process(PID = 4185)

  &nbsp; 再添加信號量(liang)的控制(zhi)部分(fen)并(bing)運行結果。

    $ ./sem_fork
    /* 子進程在運行中,父進程在等待子進程結束 */
    Child process will wait for some seconds…
    The returned value is 0 in the child process(PID = 4185) /* 子進程結束了 */
 &nbsp;  The returned value is 4185 in the father process(PID = 4184) /* 父進程結束*/

    本實例說明了使用信號(hao)量(liang)怎么解決多進程間存在(zai)的(de)同步問題。我們將在(zai)后面講述的(de)共享(xiang)內(nei)存和消息(xi)隊列的(de)實例中,看(kan)到(dao)使用信號(hao)量(liang)實現多進程之間的(de)互斥。

    本文選自華清遠見嵌入式培訓教材《從實踐中學嵌入式Linux應用程序開發》

   熱點鏈接:

   1、linux下的信號處理實例
   2、信號處理函數signal()和信號集函數組
   3、信號捕捉函數alarm()和pause()
   4、信號發送函數kill()和raise()
   5、Linux下的信號機制

更多新聞>>