進程通信之共享內存與信號量

信號量:通過設置一個值val大於0的整數,表示當前最多允許val個進程進入臨界區。同時定義P函數,函數中對val進行減1操作,每當一個進程進入臨界區時執行一次P函數,當val爲0時當前進程等待。定義V函數,對val進行加1操作,當一個進程離開臨界區執行V函數。
結構如下:

P();
//臨界區
V();

linux下封裝了對信號量的操作函數semget semop semctl需要引用頭文件#include <sys/sem.h>
有些情況下可能會用到頭文件sys/types.t和sys/ipc.h

semid = semget((key_t)1234,1,IPC_CREAT|0666);1表示創建信號量集中信號量的個數,常用1。

sem_union.val = 1;//設置信號量的值爲1,sem_union位聯合體自己定義
semctl(semid,0,SETVAL,sem_union);0爲常用,SETVAL表示設置信號量的值。

struct sembuf sem_b;
sem_b.sem_num = 0;//常用
sem_b.sem_op = 1;//1爲V操作 -1爲P操作
sem_b.sem_flg = SEM_UNDO;//常用
semop(semid,&sem_b,1);//1表示參數2表示的數組元素個數


共享內存用於多個進程之間互相通信。linux封裝以下函數進行操作。
shmget shmat shmdt shmctl
其中shmget((key_t)1234,1024,IPC_CREAT|0666),1024表示共享內存空間大小,IPC_CREAT|0666表示訪問權限和不存在就創建。

刪除共享內存空間:shmctl(shmid,IPC_RMID,NULL);shmid爲shmget的返回值。

使用共享內存之前需要將共享內存附加到進程的內存空間:shmat(shmid,NULL,0)表示由系統決定附加到的空間位置,不推薦自己指定。shmat返回一個void指針類型,可以強制轉化成其他數據類型,用來進行數據傳遞。如int *data = shmat();

當不使用該共享內存時,需要將它與進行分離。shmdt(data);將shmat的指針傳進來即可。

需要頭文件<sys/shm.h>


接下來給出兩段代碼綜合使用了信號量和共享內存。這兩段代碼大同小異。在semc1.c中將共享內存的值改爲1,在semc2.c中輸出共享值,並將共享值改爲2。分別睡眠不同時間。

//semc1.c
#include <stdio.h>
#include <unistd.h>

#include <sys/sem.h>
#include <sys/shm.h>

union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};

int sem_p();
int sem_v();

int semid;

int main(int argc,char *argv[])
{
    int flag,i,shmid,*shmdata;
    key_t key;
    union semun sem_union;

    flag = IPC_CREAT|0666;  

    key = ftok(".",'a');
    if(key == -1)
        return -1;

    semid = semget(key,1,flag);//cluster contain 1 sem
    if(semid == -1)
        return -1;

    shmid = shmget(key,1024,flag);
    shmdata = (int *)shmat(shmid,NULL,0);

    sem_union.val = 1;
    semctl(semid,0,SETVAL,sem_union);

    for(i=0;i<10;i++)
    {
        if(!sem_p())
            return -1;
        *shmdata = 1;
        if(!sem_v())
            return -1;
        sleep(2);
    }

    shmdt(shmdata);
    shmctl(shmid,IPC_RMID,NULL);
    semctl(semid,0,IPC_RMID,sem_union);

    return 0;
}

int sem_p()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(semid,&sem_b,1)==-1)
        return 0;
    return 1;
}

int sem_v()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(semid,&sem_b,1)==-1)
        return 0;
    return 1;
}

//semc2.c

#include <stdio.h>
#include <unistd.h>

#include <sys/sem.h>
#include <sys/shm.h>

int sem_p();
int sem_v();

int semid;

int main(int argc,char *argv[])
{
    int flag,i,shmid,*shmdata;
    key_t key;

    flag = IPC_CREAT|0666;

    key = ftok(".",'a');
    if(key == -1)
        return -1;

    semid = semget(key,1,flag);//cluster contain 1 sem
    if(semid == -1)
        return -1;

    shmid = shmget(key,1024,flag);
    shmdata = (int *)shmat(shmid,NULL,0);

    for(i=0;i<10;i++)
    {
        if(!sem_p())
            return -1;
        printf("%d",*shmdata);
        *shmdata = 2;
        if(!sem_v())
            return -1;
        usleep(1500000);
    }
    shmdt(shmdata);
    return 0;
}

int sem_p()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = -1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(semid,&sem_b,1)==-1)
        return 0;
    return 1;
}

int sem_v()
{
    struct sembuf sem_b;
    sem_b.sem_num = 0;
    sem_b.sem_op = 1;
    sem_b.sem_flg = SEM_UNDO;
    if(semop(semid,&sem_b,1)==-1)
        return 0;
    return 1;
}

運行結果應該是1和2混合出現。

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