进程间通讯之信号量(实例)
2017-04-18 21:58
260 查看
1、信号量
特点:1、信号量是一个计数器,用于多进程对共享数据对象的访问。
2、信号量的初始值是任一正数,说明有多少个共享资源单位可供共享应用。(常用的信号量形式:初始值为1,即某一资源某一时刻只能给单一进程占有。称为二元信号量或双态信号量)。
控制过程:
①、测试控制该资源的信号量。
②、若信号量的值为正,则进程可以使用该资源。进程将信号量的值减1,表示它使用了一个资源单位。
③、若信号量的值为0,则进程进入休眠状态,直到进程信号量大于1.进程被唤醒,再返回①。
④、当进程不在使用共享资源的时候,该信号量的值+1。若其它有进程等待此信号量,则唤醒它。
应用:
常用于进程的同步,例如多进程项目的log打印或写文件。
2、信号量集
信号量集:信号量的集合当创建一个信号量集时,要指定该集合中信号量的数量
创建信号量集(semget)与对其赋初值(semctl)应一起,不要分开。
a、创建信号量 或 获取现在存的信号量:
int semget(key_t key,int nsems,int flag)
key:键值
nsems:表示信号量的数量
flag :同msgget
b、操作一个现有的信号量
int semctl(int semid,int semnum,int cmd,.../* union semun arg */)
semid:semget返回的信号量ID
semnum: [0] -- [nsems-1]信号量集合,即有nsems个信号量
c、操作信号量资源
int semop(int semid,struct sembuf semoparray[],size_t nops) //nops 操作几个信号量
3、实例
3.1、semget、semctl
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define NR 5 #define OP_ALL int main(void) { int i,ret,semid; //NR:信号量数组中的信号量个数 semid=semget(0x555,NR,IPC_CREAT|0644);//0x555键值,随便写的一个全局的键值 if(semid==-1) { perror("semget"); return 1; } printf("semid:%d\n",semid); //--------------设置信号量值------------------------ #ifndef OP_ALL//逐一赋值 for(i=0;i<NR;i++) { ret=semctl(semid,i,SETVAL,1); if(ret==-1) return 2; } #else//整体赋值 unsigned short val[NR]={1,1,1,1,1}; ret=semctl(semid,0,SETALL,val); if(ret==-1) return 2;//error #endif // //---------------get semval------------------------- #ifndef OP_ALL//逐一获取 for(i=0;i<NR;i++) { ret=semctl(semid,i,GETVAL); if(ret==-1) return 3; printf("%dth==>val:%d\n",i,ret); } #else//整体获取 unsigned short temp[NR]; ret=semctl(semid,0,GETALL,temp); if(ret==-1) return 3;//error for(i=0;i<NR;i++) printf("%dth==>val:%d\n",i,temp[i]); #endif // //--------------------------------------------------- getchar(); printf("===============del sem array==========\n"); semctl(semid,0,IPC_RMID);//删除信号量 return 0; }
3.2、父子进程同步打印字符(semop应用)
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define NR 1 //申请资源 void p_lock(int semid); //释放资源 void v_unlock(int semid); int main(void) { pid_t pid; int ret,semid; semid=semget(0x555,NR,IPC_CREAT|0644); if(semid==-1) return 11; ret=semctl(semid,0,SETVAL,10); if(ret==-1) return 22; //------------------------------------------ pid=fork(); if(pid==-1) return 1; else if(pid==0) //child { char i,*str="1234567890"; for(i=0;str[i];i++) { p_lock(semid); write(STDOUT_FILENO,str+i,1); usleep(500000); v_unlock(semid); } exit(0); } //parent char i,*str="abcdefghij"; for(i=0;str[i];i++) { p_lock(semid); write(STDOUT_FILENO,str+i,1); sleep(2); v_unlock(semid); } wait(NULL); putchar('\n'); return 0; } void p_lock(int semid) { struct sembuf buf={.sem_num=0,.sem_op=-10}; semop(semid,&buf,1); } void v_unlock(int semid) { struct sembuf buf={.sem_num=0,.sem_op= 10}; semop(semid,&buf,1); }
3.3、文件同步写
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <sys/wait.h> #include <sys/ipc.h> #include <sys/sem.h> #define TIMES 1000000 static int semid; void write_file(int fd); void unlock(void); void lock(void); int main(void) { int ret,fd,val=0; pid_t pid; fd=open("./txt",O_RDWR|O_TRUNC|O_CREAT,0644); if(fd==-1) return 1; pwrite(fd,&val,sizeof(int),0); //---------------------------------------- semid=semget(0x555,1,IPC_CREAT|0644);//创建一个信号量 if(semid==-1) return 11; ret=semctl(semid,0,SETVAL,1);//设置一个信号量,资源为1 if(ret==-1) return 22; //----------------------------------------- pid=fork(); if(pid==-1) return 2;//error else if(pid==0) //child { printf("child start......\n"); write_file(fd); printf("child write file over\n"); close(fd); exit(0); } //parent printf("parent write file\n"); write_file(fd); wait(NULL); pread(fd,&val,sizeof(int),0); printf("====>val:%d\n",val); close(fd); return 0; } void write_file(int fd) { int i,val; for(i=0;i<TIMES;i++) { //lock lock(); pread(fd,&val,sizeof(int),0); val+=1; pwrite(fd,&val,sizeof(int),0); unlock(); //unlock } } void lock(void) { struct sembuf buf={.sem_op=-1,.sem_num=0}; semop(semid,&buf,1); } void unlock(void) { struct sembuf buf={.sem_op=1,.sem_num=0}; semop(semid,&buf,1); }
3.4、等0操作
#include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #define NR 1 void v_unlock(int semid); void p_lock(int semid); int main(void) { int i,ret,semid; pid_t pid; semid=semget(0x666,NR,IPC_CREAT|0644); if(semid==-1) return 1; ret=semctl(semid,0,SETVAL,10); if(ret==-1) return 2; pid=fork(); if(pid==-1) return 1; else if(pid==0) //child { while(1) { for(i=0;i<10;i++) { p_lock(semid); printf("===child:%d=====\n",i); sleep(1); } } } //parent struct sembuf zero={.sem_num=0,.sem_op=0}; while(1) { //wait zero semop(semid,&zero,1); printf("==========parent=========\n"); v_unlock(semid); } return 0; } void v_unlock(int semid) { struct sembuf buf={.sem_num=0,.sem_op=10}; semop(semid,&buf,1); } void p_lock(int semid) { struct sembuf buf={.sem_num=0,.sem_op=-1}; semop(semid,&buf,1); }
3.5、栅栏程序模型
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <signal.h> #define NR 5 static int semid; void sigfunc(int signo) { if(signo!=SIGINT) return; semctl(semid,0,IPC_RMID); exit(0); } void do_work(int index); void p_lock(int index); int main(void) { int i; pid_t pid; signal(SIGINT,sigfunc);//is error //------create sem----------------- //对应的信号量用控制对应的子进程 最后一个用于父进程控制周期 semid=semget(0x555,NR+1,IPC_CREAT|0644); if(semid==-1) { perror("semget"); return 1; } unsigned short val[NR+1]={0}; i=semctl(semid,0,SETALL,val); if(i==-1) { perror("semctl"); return 2; } //----------------------------------- for(i=0;i<NR;i++) { pid=fork(); if(pid==-1) return 1; else if(pid==0)//child { do_work(i); exit(0); } } //---------------给定子进程资源--------------- struct sembuf ar[NR+1],zero={.sem_num=NR,.sem_op=0}; for(i=0;i<NR;i++) { ar[i].sem_op =1; ar[i].sem_num=i; } ar[NR].sem_num=NR; ar[NR].sem_op =NR; //----------------------------------- while(1) { semop(semid,&zero,1);//等0操作 printf("==========================\n"); semop(semid,ar,NR+1); } while(wait(NULL)!=-1) ;//empty return 0; } void do_work(int index) { int sec; srand(getpid()); while(1) { p_lock(index); sec=rand()%6+1; sleep(sec); printf("%d:[%d] sleep:%d\n",index,getpid(),sec); //通知父进程已跑完 p_lock(NR); } } void p_lock(int index) { struct sembuf s={.sem_num=index,.sem_op=-1}; if(semop(semid,&s,1)==-1) { perror("semop"); exit(1); } }
相关文章推荐
- Android应用中通过AIDL机制实现进程间的通讯实例
- Linux下用fork()派生的子进程通过pipe管道通讯的实例详解("生产者-消费者"问题)
- linux进程之间通讯常用信号
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 信号应用实例
- 进程间通讯概述管道通讯信号通讯共享内存
- 进程间通讯(一) --- 信号
- Android应用中通过AIDL机制实现进程间的通讯实例
- APUE学习笔记—— 信号实现系统sleep和system函数,解决进程竞争实例
- 初步理解Python进程的信号通讯
- Linux进程间通讯之信号量
- Android应用中通过AIDL机制实现进程间的通讯实例
- Android应用中通过AIDL机制实现进程间的通讯实例
- 进程通讯之共享内存实例
- Android应用中通过AIDL机制实现进程间的通讯实例
- Android应用中通过AIDL机制实现进程间的通讯实例
- 实例解析C++/CLI程序进程之间的通讯
- Android应用中通过AIDL机制实现进程间的通讯实例
- Android应用中通过AIDL机制实现进程间的通讯实例
- 【原创】《Linux高级程序设计》杨宗德著 - 进程管理与程序开发 - 信号应用实例 分类: Linux --- 应用程序设计 2014-11-09 11:33 66人阅读 评论(0) 收藏
- 实例解析C++/CLI程序进程之间的通讯