linux進程間的通信機制--信號量互斥

1.核心理論

  • 進程互斥:多個併發的進程互相排斥的按照一定的先後順序訪問臨街資源的過程叫做進程互斥。

  • 信號量的實質:數字

  • 信號量的操作:獲取信號量(減法),釋放信號量(加法)。

  • 信號量概念:信號量又名信號燈,與其他進程間的通信方式大不相同,主要用途是保護臨界資源(進程互斥)。此外進程可以根據它判定是否能夠訪問某些共享資源。除了用於訪問控制外,還用於進程同步。

  • 信號量分類:

  • 二值信號燈:信號燈的值只能取值0或者1。
    計數信號燈:信號燈的值可以去任意的非負值。

2.函數學習:

  • 創建信號量
    函數名:semget
    函數原型:int semget(key_t key , int nsems , int semflg)
    功能:獲取信號量集合的標識符。此外當key所指定的信號量不存在的時候,並且semflg裏面包含了IPC_CREAT,這時候就會創建一個信號量集合。
    頭文件:sys/types.h sys.ipc.h sys/sem.h
    返回值:成功:返回信號量的標識符。失敗-1
    參數說明:key:鍵值。 emflg:標誌,可取IPC_CREATnsems:創建的這個信號集合裏面所包含的信號量的數目。

注意:
信號量用法:信號的操作方法和文件的操作方法相似,首先打開信號量獲取信號量的描述符;然後通過描述符來操作信號量。

  • 操作信號量:
    函數名:semop
    函數原型:int semop(int semid , struct sembuf *sops, unsigned nops)
    功能:操作信號量集合裏面的信號量
    頭文件:sys/types.h sys.ipc.h sys/sem.h
    返回值:成功0,失敗 -1
    參數:
    semid:要操作信號量集合的標識符
    nsops:要操作多少個信號量
    sops:對信號執行什麼樣的操作

  • 信號量的控制
    函數名:semctl
    函數原型:int semctl(int semid , int semnum , int cmd,...)
    頭文件:sys/types.h sys.ipc.h sys/sem.h
    功能:對信號量進行操作
    返回值:成功返回操作結果,失敗-1
    參數:semid:要操作信號量集合的標識符,semnum:操作的信號量,cmd:操作方法(常用的操作命令有GETVAL:獲取信號量的值,SETVAL:設置信號量的值)

注意:鍵值

  • 關於鍵值的理解
    鍵值含義:文件通過文件名來獲取文件描述符,而信號量則通過鍵值來獲取信號量的標識符。

  • 指定鍵值的方法:
    (1)任意指定一個數。這樣做的缺點是這個數已經被別的IPC對象(消息隊列,共享內存)所使用了,在於新創建的信號量相關連時就會失敗
    (2)構造一個儘量不被別的IPC對象所使用到的數字。
    方法:使用ftok函數

  • 構造鍵值的函數
    函數名:ftok
    函數原型:key_t ftok(char *fname ,int id)
    頭文件:sys/types.h sys.ipc.h
    功能:構造一個新的鍵值
    返回值:成功返回一個鍵值,失敗-1
    參數:fname:文件名 id:項目id

  • ftok函數工作原理:將文件名在內核中與之對應的數字與項目id組合起來形成一個鍵值(這兩個組合的鍵值是固定的且唯一的)。

3.信號量互斥編程實例:

  • 解決公告板問題
    student1去公告板寫入一段字符,期間休息10s,student2在student1休息期間也寫入一串字符,結果導致公告板的信息就是studen1想要表達的,也不是student2想要表達。
    爲了防止這種糟糕情況的出現,於是引入了信號量,student1.在未完成寫入之前不會釋放信號量,student2得不到信號量,就無法使用公告板,從而避免上述情形的出現。

  • student1.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdio.h>

void main()
{
    int fd;
    key_t key;
    int semid;
    int ret;
    struct sembuf sops;

    key = ftok("/home",1);//創建鍵值

    semid = semget(key,1,IPC_CREAT);//創建並打開信號量集合
    semctl(semid,0,SETVAL,1);//設置信號量的值爲1

    fd = open("./board.txt",O_RDWR|O_APPEND);//打開文件

    sops.sem_num = 0;//要設置的信號量
    sops.sem_op =  -1;//執行-1操作
    semop(semid,&sops,1);//獲取信號量

    ret = semctl(semid,0,GETVAL);//獲取信號量的值
    printf("The semval is %d\n",ret);

    write(fd,"class math",10);//寫入字符
    sleep(10);//休息
    write(fd," is cancel",9);//再次寫入

    sops.sem_num = 0;
    sops.sem_op = 1;//執行加一操作
    semop(semid,&sops,1);//釋放信號量

    close(fd);
}
  • student2.c
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>

void main()
{
    int fd;
    key_t key;
    int semid;
    int ret;
    struct sembuf sops;

    key = ftok("/home",1);//指定鍵值
    semid = semget(key,1,IPC_CREAT);//創建信號量
    ret = semctl(semid,0,GETVAL);//獲取信號量的值
    printf("The semval is %d\n",ret);

    fd = open("./board.txt",O_RDWR|O_APPEND);//打開文件

    sops.sem_num = 0;
    sops.sem_op =- 1;
    semop(semid,&sops,1);//獲取信號量

    write(fd," class English is test",21);//寫入字符

    sops.sem_num = 0;
    sops.sem_op =+ 1;
    semop(semid,&sops,1);//釋放信號量
    ret = semctl(semid,0,GETVAL);//獲取信號量的值
    printf("The semval is %d\n",ret);

    close(fd);

}

程序執行步驟:首先執行student1進程,然後執行student2進程

執行結果:
在文件board.txt中寫入class math is cancel class English is test

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章