Linux-IPC之信号量
来源:互联网 发布:网速控制软件 编辑:程序博客网 时间:2024/06/04 17:40
信号量分为以下三种:
1、System V信号量,在内核中维护,可用于进程或线程间的同步,常用于进程的同步。
2、Posix有名信号量,一种来源于POSIX技术规范的实时扩展方案(POSIX Realtime Extension),可用于进程或线程间的同步,常用于线程。
3、Posix基于内存的信号量,存放在共享内存区中,可用于进程或线程间的同步。
为了获得共享资源进程需要执行下列操作:
(1)测试控制该资源的信号量。
(2)若信号量的值为正,则进程可以使用该资源。进程信号量值减1,表示它使用了一个资源单位。此进程使用完共享资源后对应的信号量会加1。以便其他进程使用。
(3)若信号量的值为0,则进程进入休息状态,直至信号量值大于0。进程被唤醒,返回第(1)步。
为了正确地实现信号量,信号量值的测试值的测试及减1操作应当是原子操作(原子操作是不可分割的,在执行完毕前不会被任何其它任务或事件中断)。为此信号量通常是在内核中实现的。
System V IPC机制:信号量。
函数原型:
#include <sys/sem.h>#include <sys/ipc.h>#include <sys/types.h>int semget(key_t key,int nsems,int flag);int semop(int semid,struct sembuf *sops,size_t num_sops);int semctl(int semid, int semnum, int cmd, …);
一、示例:程序被打断出错
//创建、初始化共享内存#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <stdlib.h>#include <sys/shm.h>#define PROJ_ID 1#define TIMES 1000000int main(int argc,char* argv[]){if(argc!=2){printf("error args\n");return -1;}key_t skey;skey=ftok(argv[1],PROJ_ID);if(-1==skey){perror("ftok");return -1;}printf("the key is %d\n",skey);int shmid;shmid=shmget(skey,1<<12,0600|IPC_CREAT);//创建共享内存if(-1==shmid){perror("shmget");return -1;}printf("the shmid is %d\n",shmid);int* p;p=shmat(shmid,NULL,0);if((int*)-1==p){perror("shmat");return -1;}*p=0;//初始化共享内存return 0;}
//add1.c&&add2.c分别将内存中的数加10000000次1#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <stdlib.h>#include <sys/shm.h>#define PROJ_ID 1#define TIMES 10000000int main(int argc,char* argv[]){if(argc!=2){printf("error args\n");return -1;}key_t skey;skey=ftok(argv[1],PROJ_ID);if(-1==skey){perror("ftok");return -1;}//printf("the key is %d\n",skey);int shmid;shmid=shmget(skey,1<<12,0600|IPC_CREAT);if(-1==shmid){perror("shmget");return -1;}//printf("the shmid is %d\n",shmid);int* p;p=shmat(shmid,NULL,0);if((int*)-1==p){perror("shmat");return -1;}int i;for(i=0;i<TIMES;i++){*p=(*p)+1;}printf("the value is %d\n",*p);return 0;}
两个相同的程序,功能是将共享内存中的数加10000000次1,正确的结果应该是20000000
同时运行(用脚本实现)后的结果却为:
说明在两个程序并行的时候语句被打断。
二、semget()函数
参数flag是一组标志,其作用与open函数的各种标志很相似。它低端的九个位是该信号量的权限,其作用相当于文件的访问权限。
#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <stdio.h>int main(){int semid;semid=semget((key_t)1234,10,0666|IPC_CREAT);printf("the semid is %d\n",semid);return 0;}
运行结果:
三、semctl()函数
1.参数semid是由semget返回的信号量标识符。
2.参数semnum为集合中信号量的编号,当要用到成组的信号量时,从0开始。一般取值为0,表示这是第一个也是唯一的一个信号量。
3.参数cmd为执行的操作。通常为:IPC_RMID(立即删除信号集,唤醒所有被阻塞的进程)、GETVAL(根据semun返回第GETVAL-1个信号的值,从0开始,第一个信号量编号为0)、SETVAL(根据semun设定信号的值,从0开始,第一个信号量编号为0)、GETALL(获取所有信号量的值,第二个参数为0,将所有信号的值存入semun.array中)、SETALL(将所有semun.array的值设定到信号集中,第二个参数为0)等。
参数…是一个union semun(需要由程序员自己定义),它至少包含以下几个成员:
union semun{int val;/* Value for SETVAL */struct semid_ds *buf;/* Buffer for IPC_STAT, IPC_SET */unsigned short *array;/* Array for GETALL, SETALL */};
通常情况仅使用val,给val赋值为1
在生产者源码里,首先用函数semctl()初始化信号量集合sem_id,它包含两个信号,分别表示生产的数量和空仓库的数量,那么在消费者的进程中用相同的key值就会得到该信号量集合;实现两个进程之间的通信。
在主函数里,设定对两个信号量的PV操作,然后在各自的进程中对两个信号进行操作。
(1)如果只运行生产者进程,则生产10个之后,该进程就会因为在得不到空仓库资源而阻塞,这个时候运行消费者进程,阻塞就会被解除;
(2)如果先运行生产者进程,生产几个产品之后,关闭该进程,则运行消费者进程,当消费完生产的产品后,该进程就会因为在得不到产品资源而阻塞,这个时候运行生产者进程,阻塞就会被解除;
(3)如果同时运行两个进程,由于消费比生产快,因此消费者每次都要等待生产者生产产品之后才能消费;
在每次运行程序之前,一定要先运行生产者进程先初始化信号量。
#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <stdlib.h>int main(){int semid;semid=semget((key_t)1234,1,0666|IPC_CREAT);//IPC_CREAT创建信号量if(-1==semid){perror("semget");return -1;}int ret;ret=semctl(semid,0,GETVAL);if(-1==ret){perror("semctl");return -1;}printf("ret is %d\n",ret);return 0;}
运行结果:
#include <stdio.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <stdlib.h>int main(){int semid;semid=semget((key_t)1234,1,0600|IPC_CREAT);if(-1==semid){perror("semget");return -1;}printf("the semid is %d\n",semid);int ret;ret=semctl(semid,0,GETVAL);if(-1==ret){perror("semctl");return -1;}printf("ret is %d\n",ret);ret=semctl(semid,0,SETVAL,1);//将信号量的值置1if(-1==ret){perror("semctl");return -1;}ret=semctl(semid,0,GETVAL);if(-1==ret){perror("semctl");return -1;}printf("after ret is %d\n",ret);return 0;}
//信号量集合操作#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>int main(){int semid;semid=semget((key_t)1234,3,0600|IPC_CREAT);if(-1==semid){perror("semid");return -1;}int ret;unsigned short arr[3];ret=semctl(semid,0,GETALL,arr);if(-1==ret){perror("semctl");return -1;}printf("1sem=%d,2sem=%d,3sem=%d\n",arr[0],arr[1],arr[2]);return 0;}
<pre name="code" class="cpp">#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>#include <strings.h>int main(){int semid;semid=semget((key_t)1234,3,0600|IPC_CREAT);if(-1==semid){perror("semid");return -1;}int ret;unsigned short arr[3];ret=semctl(semid,0,GETALL,arr);if(-1==ret){perror("semctl_get");return -1;}printf("1sem=%d,2sem=%d,3sem=%d\n",arr[0],arr[1],arr[2]);arr[0]=1;arr[1]=2;arr[2]=3;ret=semctl(semid,0,SETALL,arr);if(-1==ret){perror("semctl_set");return -1;}bzero(arr,sizeof(arr));ret=semctl(semid,0,GETALL,arr);if(-1==ret){perror("semctl_get");return -1;}printf("1sem=%d,2sem=%d,3sem=%d\n",arr[0],arr[1],arr[2]);return 0;}
四、semop()函数
参数semid是由semget返回的信号量标识符。
参数sops是指向一个结构体数组的指针。每个数组元素至少包含以下几个成员:
struct sembuf{short sem_num; //操作信号量在信号量集合中的编号,第一个信号量的编号是0。short sem_op;//sem_op成员的值是信号量在一次操作中需要改变的数值。通常只会用到两个值,一个是-1,也就是p操作,它等待信号量变为可用;一个是+1,也就是v操作,它发送信号通知信号量现在可用。short sem_flg;//通常设为:SEM_UNDO,程序结束,信号量为semop调用前的值。};
参数nops为sops指向的sembuf结构体数组的大小。
//初始化init.c#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#define PROJ_ID 1int main(int argc,char* argv[]){if(argc!=2){printf("error args\n");return -1;}key_t skey;skey=ftok(argv[1],PROJ_ID);if(-1==skey){perror("ftok");return -1;}printf("the key is %d\n",skey);int shmid;shmid=shmget(skey,1<<12,0600|IPC_CREAT);if(-1==shmid){perror("shmget");return -1;}printf("the shmid is %d\n",shmid);int *p;p=(int*)shmat(shmid,NULL,0);if((int*)-1==p){perror("shmat");return -1;}*p=0;printf("the value is %d\n",*p);return 0;}
//两个相同的加法程序add1.c&add2.c#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/sem.h>#include <strings.h>#define TIMES 10000000#define PROJ_ID 1int main(int argc,char* argv[]){if(argc!=2){printf("error args\n");return -1;}key_t skey;skey=ftok(argv[1],PROJ_ID);if(-1==skey){perror("skey");return -1;}printf("the skey is %d\n",skey);int shmid;shmid=shmget(skey,1<<12,0600|IPC_CREAT);if(-1==shmid){perror("shmget");return -1;}printf("the shmid is %d\n",shmid);int* p;p=(int*)shmat(shmid,NULL,0);if((int*)-1==p){perror("shmat");return -1;}int semid;semid=semget((key_t)1234,0,0600);if(-1==semid){perror("semget");return -1;}struct sembuf sop;bzero(&sop,sizeof(sop));sop.sem_num=0;sop.sem_op=-1;sop.sem_flg=SEM_UNDO;struct sembuf sov;bzero(&sov,sizeof(sov));sov.sem_num=0;sov.sem_op=1;sov.sem_flg=SEM_UNDO;int i;for(i=0;i<TIMES;i++){semop(semid,&sop,1);*p=(*p)+1;semop(semid,&sov,1);}printf("the value is %d\n",*p);return 0;}
输出结果:
- Linux-IPC之信号量
- Linux XSI IPC 之信号量
- 【Linux】IPC通信之信号量
- Linux IPC 3 之 信号量
- Linux内核IPC机制之信号量
- Linux 进程通信IPC对象之信号量
- linux IPC--信号量
- linux IPC--信号量
- IPC之信号量
- IPC(SystemV) 之 信号量
- IPC之信号量详解
- Linuc IPC之信号量
- IPC通信之信号量
- IPC之—信号量
- Linux下IPC数据结构之信号量机制模拟实现
- Linux — IPC进程通信之信号量详解
- Linux ipc------System V信号量
- linux IPC --- 有名信号量详解
- 用gdb调试运行中的程序
- 初次体验完美easy ui 1.4.4
- javascript 简单ajax 框架
- Eclipse使用hibernate插件
- 程序员从教女友写代码中学到的
- Linux-IPC之信号量
- 点击2次Back键退出程序
- DateUtils时间工具类探究
- MD5转换2
- LCIS vijos—P1264
- Java 偏向锁测试
- 上层APP调用底层硬件驱动过程解析
- 《笨办法学Python》 第25课手记
- js 自定义滑块 实现文字滚动+透明度变化