进程通信之共享内存与信号量

信号量:通过设置一个值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混合出现。

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