1. 程式人生 > >linux的ipc訊號量簡單例項

linux的ipc訊號量簡單例項

訊號量實現程序間訪問互斥的資源測試例子。
主要涉及到的函式及原型如下(加粗、顏色表示要重點關心的上下文相關變數)
1: key_tftok(char *fileName, int id);//目的獲取key值

2: intsemget(key_t key, int nsems, int semflg)//目的獲取id

3:int semctl(int semid, int semnum, int cmd, union semunarg)//目的設定訊號量的值,獲取訊號量的值等等,功能通過cmd變數控制
//其中semunarg必須由使用者自身定義,格式如下
union semun {
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
    //other linux specific
};

4: int semop(int semid, struct sembuf *sops, unsign ednsops)//目的改變訊號量的值,在sembuf中。

可通過每個函式大體功能,man手冊中查詢一些說明,進行研究測試。
以下測試程式碼非常簡單,僅僅是為了熟悉api的基本功能,如果有錯誤和需要說明的地方,歡迎指正。

#include <sys/types.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>

union semun {//semctl函式的第三個引數結構定義,現只關心設定val,其它成員可忽視,起到初始化資源數目的作用
    int val;
    // struct semid_ds *buf;
    // unsigned short *array;
    // struct seminfo *__buf;
};

int sem_init(int semid, int initval)//初始化訊號量 init val
{
    union semun arg;

    arg.val = initval;
    semctl(semid, 0, SETVAL, arg);//SETVAL 是semctl的cmd引數,意思是設定訊號量為arg.val的值,0是訊號量中第1個資源的下標
    //fixme if some error
    return 0;
}

int creat_sem(char *fileName)//建立一個訊號燈,訊號量預設寫了1個,如果沒有該訊號量,建立,如果有,獲取id
{
    int id;
    key_t key;

    key = ftok(fileName, 1);
    if (key < 0) {
        perror("ftok()");
        key = 5;//any number just for test
    }

    if ((id = semget(key, 1, IPC_CREAT | IPC_EXCL |0660)) < 0) {//1個訊號量 creat? or exist?
        if ((id = semget(key, 1, IPC_CREAT | 0660)) < 0) {//1個訊號量 if exist,only get the id
            printf("semget error: id = %d\n", id);
        }
        printf("sem allready exist: id = %d\n", id);
    } else {//init the number when first use
        sem_init(id, 0);
    }

    return id;
}

void P(int semid)//申請資源,資源數sembuf中的sem_op - 1
{
    int ret = 0;
    struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = -1;
    sb.sem_flg = 0;

    ret = semop(semid, &sb, 1);
    if (ret < 0) {
        printf("error in p(s)\n");
    }
}

void V(int semid)//釋放資源,資源數sembuf中的sem_op - 1
{
    int ret = 0;
    struct sembuf sb;
    sb.sem_num = 0;
    sb.sem_op = 1;
    sb.sem_flg = 0;

    ret = semop(semid, &sb, 1);
    if (ret < 0) {
        printf("error in v(s)\n");
    }
}

void showStat(int semid)
{
    int ret = semctl(semid, 0, GETVAL, 0);

    printf("now %d val is %d\n", semid, ret);
}

int main(int argc, char **argv)
{
    int sem_id0, sem_id1;

    if (fork() == 0) {//子程序 程序1
        sem_id0 = creat_sem("/tmp/2");
        sem_id1 = creat_sem("/tmp/3");
        V(sem_id1);
        while (1) {
            P(sem_id0);
            printf("working : process11111\n");
            showStat(sem_id0);
            showStat(sem_id1);
            sleep(1);
            V(sem_id1);
        }
    } else {//父程序 程序2
        sem_id0 = creat_sem("/tmp/2");
        sem_id1 = creat_sem("/tmp/3");
        sleep(2);
        while (1) {
            P(sem_id1);
            printf("working : process2222222222\n");
            showStat(sem_id0);
            showStat(sem_id1);
            sleep(2);
            V(sem_id0);
        }
    }

    return 0;
}