进程间通信-信号量

来源:互联网 发布:js垂直轮播广告幻灯片 编辑:程序博客网 时间:2024/06/05 02:10

system IPC中,对于每一个新建的信号量 消息队列 共享内存,都有一个在整个系统中唯一的标识符。每个标识也都有唯一对应的关键字,关键字的数据类型为ket_t

在终端输入命令 ipcs ,可以看到目前系统中所有的ipc信息

------------ 共享内存段 --------------键        shmid      拥有者  权限     字节     nattch     状态      0x00000000 1507328    tian       600        2097152    2          目标       0x00000000 884737     tian       600        1048576    2          目标       0x00000000 11141122   tian       600        2097152    2          目标       0x00000000 524291     tian       600        393216     2          目标       0x00000000 10846212   tian       600        524288     2          目标       0x00000000 720901     tian       600        524288     2          目标       0x00000000 1540102    tian       600        393216     2          目标       0x00000000 9830407    tian       600        393216     2          目标       0x00000000 1245192    tian       600        2097152    2          目标       0x00000000 1572873    tian       600        1048576    2          目标       0x00000000 3145738    tian       600        524288     2          目标       0x00000000 9994251    tian       600        12288      2          目标       0x00000000 10944524   tian       600        2097152    2          目标       0x00000000 11239437   tian       600        33554432   2          目标       --------- 信号量数组 -----------键        semid      拥有者  权限     nsems     --------- 消息队列 -----------键        msqid      拥有者  权限     已用字节数 消息  

ftok()函数用于获得一个IPC关键字,其函数原型为

#include <sys/types.h>       #include <sys/ipc.h>       key_t ftok(const char *pathname, int proj_id);
pathname 必须是一个已经存在并具有访问权限 的文件,pro_jd 只有低8位有效,常用ascii字符代替。当两个都相同时,ftok返回相同的键值。

IPC关键字可以由 ftok()函数获得,也可以设为IPC_PRIVATE ,这时系统会确保创建一个新的IPC,其标识符需要由进程自己记录并告诉其他进程。

信号量函数由semget、semop、semctl三个函数组成。

semget(得到一个信号量集标识符或创建一个信号量集对象)

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semget(key_t key, int nsems, int semflg)
nsems 创建信号量集中信号量的个数,该参数只在创建信号量集时有效

msgflg IPC_CREAT:当semflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的信号量集,则新建一个信号量集;如果存在这样的信号量集,返回此信号量集的标识符

IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的信号量集,则新建一个消息队列;如果存在这样的信号量集则报错

semop(完成对信号量的P操作或V操作)

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semop(int semid, struct sembuf *sops, unsigned nsops)

sops:指向进行操作的信号量集结构体数组的首地址,此结构的具体说明如下:

struct sembuf {

    unsighed short semnum;

    short sem_op;

    short sem_flag

  };


struct sembuf sem_get={0,-1,IPC_NOWAIT}; /*将信号量对象中序号为0的信号量减1*/

struct sembuf sem_get={0,1,IPC_NOWAIT};  /*将信号量对象中序号为0的信号量加1*/

struct sembuf sem_get={0,0,0};           /*进程被阻塞,直到对应的信号量值为0*/

flag一般为0,若flag包含IPC_NOWAIT,则该操作为非阻塞操作。若flag包含SEM_UNDO,则当进程退出的时候会还原该进程的信号量操作,这个标志在某些情况下是很有用的,比如某进程做了P操作得到资源,但还没来得及做V操作时就异常退出了,此时,其他进程就只能都阻塞在P操作上,于是造成了死锁。若采取SEM_UNDO标志,就可以避免因为进程异常退出而造成的死锁。

#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int semctl(int semid, int semnum, int cmd, union semun arg)
常用的cmd有,SETVAL,用联合体中val成员的值设置信号量集合中单个信号量的值

IPC_RMID 立即删除信号量集

例子:

#include <stdarg.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <errno.h>#include <linux/ipc.h>#include <linux/sem.h>#include <linux/shm.h>#if 0union semun{    int val; /*val for SETVAL*/    struct semid_ds *bur; /*buffer for IPC_STAT,IPC_SET*/    unsigned short *array; /*array for getall,setall*/    struct seminfo *_buf; /*buffer for IPC_INFO*/};#endif /*define a function pid_printf*/void pid_printf(char *format, ...){    va_list ap;    va_start(ap, format);    printf("[%d]%d:", getpid(),__LINE__);    vprintf(format, ap);}/*release sem*/void sem_release(int id){    struct sembuf sb;        sb.sem_num = 0;    sb.sem_op = 1;    sb.sem_flg = SEM_UNDO;        pid_printf("releaseing..\n");    if(semop(id, &sb, 1) == -1)    {        pid_printf("semop");        exit(-1);    }    pid_printf("releassed OK.\n");}/*request sem*/void sem_request(int id){    struct sembuf sb;        sb.sem_num = 0;    sb.sem_op = -1;    sb.sem_flg = SEM_UNDO;        pid_printf("requesting..\n");    if(semop(id, &sb, 1) == -1)    {        pid_printf("semop error!\n");        exit(-1);    }    printf("request OK!\n");}/*delete sem*/void sem_delete(int id){    printf("master exiting; delete sem\n");    if(semctl(id, 0, IPC_RMID, 0) == -1)    {        pid_printf("error relesing sem\n");    }}int main(int argc, char *argv[]){    int id;    union semun sun;    if(argc < 2)    {        id = semget(IPC_PRIVATE, 1, SHM_R|SHM_W);        if(id != -1)        {            sun.val = 1;            if(semctl(id, 0, SETVAL, sun) == -1)            {                pid_printf("semctl failed\n");                exit(-1);            }        }    }    else    {        id = atoi(argv[1]);        pid_printf("using existing sem [%d]\n", id);    }        if(id == -1)    {        pid_printf("sem request failed...\n");        return 0;    }        pid_printf("sucessfully! id=[%d]\n", id);        while(1)    {        int action;        printf("1.Release\n");        printf("2.Request\n");        printf("3.Exit-delete\n");        printf("Your choice:");                scanf("%d", &action);        switch(action)        {            case 1:                sem_release(id);                break;            case 2:                sem_request(id);                break;            case 3:                sem_delete(id);                exit(0);                break;        }            }    return 0;}



0 0
原创粉丝点击