信号量P/V操作以及共享资源的使用"/>
对信号量P/V操作以及共享资源的使用
共享内存(SHM) 共享内存是效率最高的 IPC,因为他抛弃了内核这个“代理人”,直截了当地将一块裸 露的内存放在需要数据传输的进程面前,让他们自己搞,这样的代价是:这些进程必须小心 谨慎地操作这块裸露的共享内存,做好诸如同步、互斥等工作,毕竟现在没有人帮他们来管 理了,一切都要自己动手。也因为这个原因,共享内存一般不能单独使用,而要配合信号量、 互斥锁等协调机制,让各个进程在高效交换数据的同时,不会发生数据践踏、破坏等意外。 共享内存的思想很朴素,进程与进程之间虚拟内存空间本来相互独立,不能互相访问的, 但是可以通过某些方式,使得相同的一块物理内存多次映射到不同的进程虚拟空间之中,这 样的效果就相当于多个进程的虚拟内存空间部分重叠在一起,看示意图。 使用共享内存的一般步骤是: 1 ,获取共享内存对象的 ID 2 ,将共享内存映射至本进程虚拟内存空间的某个区域 3 ,当不再使用时,解除映射关系 4 ,当没有进程再需要这块共享内存时,删除它 信号量(SEM) 信号量 SEM全称 Semaphore,中文也翻译为信号灯。作为system-V IPC 的最后一种,信号量跟前面的 MSG 和 SHM 有极大的不同, SEM 不是用来传输数据的, 而是作为“旗语”,用来协调各进程或者线程工作的。 一些基本概念如下: 1 ,多个进程或线程有可能同时访问的资源(变量、链表、文件等等)称为共享资源, 也叫临界资源(critical resources)。 2 ,访问这些资源的代码称为临界代码,这些代码区域称为临界区(critical zone)。 3 ,程序进入临界区之前必须要对资源进行申请,这个动作被称为 P 操作,这就像你要 把车开进停车场之前,先要向保安申请一张停车卡一样, P 操作就是申请资源,如果申请成 功,资源数将会减少。如果申请失败,要不在门口等,要不走人。 4 ,程序离开临界区之后必须要释放相应的资源,这个动作被称为 V 操作,这就像你把 车开出停车场之后,要将停车卡归还给保安一样, V 操作就是释放资源,释放资源就是让资 源数增加。 所有一起访问共同临界资源的进程都必须遵循以上游戏规则,否则大家就都乱套了,但 是值得注意的是:这些规则是自愿的,如果有进程就是胡来——在访问资源之前不申请,那 么将会可能导致逻辑谬误,就像开车压死保安直接撞进停车场一样,虽然于情于理都不可以, 物理上阻止不了这种行为。 system-V 的信号量非常类似于停车场的卡牌,想象一个有 N 个车位的停车场,每个 车位是立体的可升降的,能停 n 辆车,那么我们可以用一个拥有 N 个信号量元素,每个信 号量元素的初始值等于 n 的信号量来代表这个停车场的车位资源——某位车主要把他的 m 辆车开进停车场,如果需要 1 个车位,那么必须对代表这个车位的信号量元素申请资源, 如果 n 大于等于 m ,则申请成功,否则不能把车开进去。对 于共享内存和信号量的使用
发送端代码如下jack.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/shm.h>#include <sys/ipc.h> #include <sys/sem.h>#include <unistd.h>#include <stdlib.h>union semun
{int val; /* 当 cmd 为 SETVAL 时使用 */ struct semid_ds *buf; /* 当 cmd 为 IPC_STAT 或 IPC_SET 时使用 */unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */struct seminfo *__buf; /* 当 cmd 为 IPC_INFO 时使用 */
};char * shm_init()
{//获取KEY值int key=ftok("./",'K');int shm_id=shmget(key, 4096,IPC_CREAT|0666);if(shm_id==-1){perror("shmget id erorr");exit(1);//直接结束进程}//映射共享内存char *shm_map=shmat(shm_id, NULL, 0);if(shm_map==(void *)-1){perror("shm map error");exit(1);//直接结束进程}return shm_map;}int sem_init()
{//获取新的KEY值int key=ftok("./",'X');//获取信号量的IDint sem_id=semget(key, 2, IPC_CREAT|0644);if(sem_id==-1){perror("sem get id error ");exit(1);}//初始化信号量的内容 主要是初始化他们的初始化的资源数//初始化没有数据,有一个空间union semun set;set.val=0; semctl(sem_id, 0, SETVAL, set); //0 初始化数据资源set.val=1; semctl(sem_id, 1, SETVAL,set ); //1 初始化空间资源return sem_id;
}int main(int argc, char const *argv[])
{//配置共享内存并初始化char *shm_map=shm_init();//初始化信号量int sem_id=sem_init();//再写入共享内存之前需要现申请一个空间资源/* struct sembuf { unsigned short sem_num; /* 信号量元素序号(数组下标) short sem_op; /* 操作参数 *short sem_flg; /* 操作选项 };*/struct sembuf space={ //设置空间资源 .sem_num=1, //需要设置的空间资源元素下表为1.sem_flg=0, //设置标记为0 啥也不选.sem_op=-1 //-1表示资源量即将建议 申请资源};struct sembuf data={ //设置空间资源 .sem_num=0, //需要设置的空间资源元素下表为0.sem_flg=0, //设置标记为0 啥也不选.sem_op=1 //1表示资源量即将加1 释放资源};while (1){//等待空间资源 会阻塞 如果资源暂时不能得到则会阻塞等待semop(sem_id, &space, 1);printf("请输入需要发送的数据\n"); fgets(shm_map,4096,stdin);//设置数据资源为1 semop(sem_id, &data, 1);/* code */}return 0;
}
接收端代码 rocs.c
#include<stdio.h>
#include <sys/types.h>
#include <sys/shm.h>#include <sys/ipc.h> #include <sys/sem.h>#include <unistd.h>#include <stdlib.h>union semun
{int val; /* 当 cmd 为 SETVAL 时使用 */ struct semid_ds *buf; /* 当 cmd 为 IPC_STAT 或 IPC_SET 时使用 */unsigned short *array; /* 当 cmd 为 GETALL 或 SETALL 时使用 */struct seminfo *__buf; /* 当 cmd 为 IPC_INFO 时使用 */
};char * shm_init()
{//获取KEY值int key=ftok("./",'K');int shm_id=shmget(key, 4096,IPC_CREAT|0666);if(shm_id==-1){perror("shmget id erorr");exit(1);//直接结束进程}//映射共享内存char *shm_map=shmat(shm_id, NULL, 0);if(shm_map==(void *)-1){perror("shm map error");exit(1);//直接结束进程}return shm_map;}int sem_init()
{//获取新的KEY值int key=ftok("./",'X');//获取信号量的IDint sem_id=semget(key, 2, IPC_CREAT|0644);if(sem_id==-1){perror("sem get id error ");exit(1);}//初始化信号量的内容 主要是初始化他们的初始化的资源数//初始化没有数据,有一个空间union semun set;set.val=0; semctl(sem_id, 0, SETVAL, set); //0 初始化数据资源set.val=1; semctl(sem_id, 1, SETVAL,set ); //1 初始化空间资源return sem_id;
}int main(int argc, char const *argv[])
{//配置共享内存并初始化char *shm_map=shm_init();//初始化信号量int sem_id=sem_init();//再写入共享内存之前需要现申请一个空间资源/* struct sembuf { unsigned short sem_num; /* 信号量元素序号(数组下标) short sem_op; /* 操作参数 *short sem_flg; /* 操作选项 };*/struct sembuf space={ //设置空间资源 .sem_num=1, //需要设置的空间资源元素下表为1.sem_flg=0, //设置标记为0 啥也不选.sem_op=1 //1表示资源量即将加以 释放资源};struct sembuf data={ //设置空间资源 .sem_num=0, //需要设置的空间资源元素下表为0.sem_flg=0, //设置标记为0 啥也不选.sem_op=-1 //1表示资源量即将加1 释放资源};while (1){printf("wait 数据\n");//等待数据资源 会阻塞 如果资源暂时不能得到则会阻塞等待semop(sem_id, &data, 1);printf("Jacl 说:%s\n",shm_map);//设置空间资源为1 semop(sem_id, &space, 1);/* code */}return 0;
}
更多推荐
对信号量P/V操作以及共享资源的使用
发布评论