信号量实现进程之间通信
一.信号量
信号量是一种数据操作锁,本身不具有数据交换功能,而是通过控制其他的通信资源来实现进程之间的通信,简单来讲,信号量相当于一个计数器,计数当前某种资源的个数。信号量的周期也是随内核的。为了解决多个程序同时访问一个共享资源引发的问题。
临界资源:多个进程能访问到的公共资源。
临界区:将能访问带临界资源的代码成为临界区。
同步:对临界资源的访问具有顺序性。
pv 操作:
p(sv) sv>0 减1 sv=0 挂起的该进程执行
s(sv) 没有进程因等待sv而挂起就加1,有进程等待sv被挂起,就恢复运行。
信号量用到的函数:
int semget(key_t key,int nsems,int smflag)//nsems:信号量个数
以信号量集为基本单位进行申请。
int semctl(int semid, int semnum, int cmd, ...);//semnum:第几个信号量
struct sembuf
{
unsigned short sem_num;
short sem_op;
short sem_flg;
}
第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信 号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。
最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量, 如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清理我们的信号量。
semnu 的联合体,初始化信号量的时候用得到:
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
信号量实现进程间通信:
//comm.h12#pragmaonce3#include<unistd.h>4#include<stdlib.h>5#include<stdio.h>6#include<sys/types.h>7#include<sys/sem.h>8#include<sys/ipc.h>9#define_PATH_"."10#define_PROJ_ID_0x77771112unionsemun13{14intval;15structsemid_ds*buf;16unsignedshort*array;17structseminfo*_buf;18};19staticintcomm(int__sem_nums,intflag);20intcreate_sem_set(int_sem_nums);21intget_sem_set(int_sem_nums);22intinit_sem_set(int_sem_id,int_sem_num,int_sem_val);23intp_sem_elem(int_sem_id,int_sem_num);24intv_sem_elem(int_sem_id,int_sem_num);25intdestroy_sem(int_sem_id);~//comm.c1#include"comm.h"2staticintcomm(int_sem_nums,intflag)3{4key_tkey=ftok(_PATH_,_PROJ_ID_);5if(key<0)6{7perror("ftok");8return-1;9}10intsem_id=semget(key,_sem_nums,flag);11if(sem_id<0)12{13perror("semget");14return-1;15}1617returnsem_id;1819}20intcreate_sem_set(int_sem_nums)21{22intflag=IPC_CREAT|IPC_EXCL|0666;23returncomm(_sem_nums,flag);242526}27intget_sem_set(int_sem_nums)28{29intflag=IPC_CREAT;30returncomm(_sem_nums,flag);31}32intinit_sem_set(int_sem_id,int_sem_num,int_sem_val)33{34unionsemun_un;35_un.val=_sem_val;36if(semctl(_sem_id,_sem_num,SETVAL,_un)<0)37{38perror("semctl");39return-1;4041}42return0;43}44intp_sem_elem(int_sem_id,int_sem_num)45{46structsembuf_sem_buf[1];47_sem_buf[0].sem_num=_sem_num;48_sem_buf[0].sem_op=-1;49_sem_buf[0].sem_flg=0;50if(semop(_sem_id,_sem_buf,1)<0)51{52perror("semop");53return-1;5455}56return0;57}58intv_sem_elem(int_sem_id,int_sem_num)59{60structsembuf_sem_buf[1];61_sem_buf[0].sem_num=_sem_num;62_sem_buf[0].sem_op=1;63_sem_buf[0].sem_flg=0;64if(semop(_sem_id,_sem_buf,1)<0)65{66perror("semop");67return-1;6869}70return0;71}74intdestroy_sem(int_sem_id)75{76if(semctl(_sem_id,0,IPC_RMID,NULL)<0)77{78perror("semctl");79return-1;808182}83return0;}91intmain()92{93intsem_id=create_sem_set(1);94init_sem_set(sem_id,0,1);95pid_tpid=fork();96if(pid<0)97{98perror("fork");99exit(1);100}101102elseif(pid==0)103{104intsem_id=get_sem_set(1);105while(1)106{107p_sem_elem(sem_id,0);108printf("A");109sleep(1);110fflush(stdout);111printf("A");112sleep(7);113fflush(stdout);114v_sem_elem(sem_id,0);116}117}118119else120{121while(1)122{123p_sem_elem(sem_id,0);124125printf("B");126sleep(2);127fflush(stdout);128printf("B");129sleep(5);130fflush(stdout);131v_sem_elem(sem_id,0);132133134}135}return0;}
程序运行结果:
总结:
上述程序中显示器就相当于公共资源,父子进程都想要访问,在其上面输出自己的内容,就必须使用信号量,这样就防止了两个同时输出引发的问题,两个进程只能一个访问完,另一个在访问。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。