Linux进程间通信的信号量是一个变量,也是一个特殊的变量。它取正值。信息量只有两种运算:
很难理解等待发送的信号数量。让我们一个一个地看看每个功能。与信号量处理相关的函数有:SEM get();SEM CTL();semop();
使用格式:
# includes ys/SEM . hintsemget(key _ t _ key,int_nsems,int _ SEM flg);函数:创建一个新的信号量或获取一个现有信号量的键值。
返回值:成功返回信号量的标识码ID。未能返回-1;
参数:
_key是一个整数值,可以由用户自己设置。有两种情况:
1.键值是IPC_PRIVATE,通常是0,意思是创建一个只能由进程给我的信号量。
2.键值不是IPC_PRIVATE。我们可以指定一个键值,比如1234;您还可以使用ftok()函数来获取唯一的键值。
_nsems表示初始化信号量的数量。例如,如果我们想创建一个信号量,值是1。如果我们创建两个,就是2。
_semflg:信号量的创建方法或权限。有IPC_CREAT和IPC_EXCL。
如果信号量不存在,创建一个信号量,否则获取。
IPC_EXCL只有当信号量不存在时,才会创建新的信号量,否则会产生错误。
让我们看一个小例子:
# includesdio . h # includes ys/SEM . h # definemykey 6666 int main(){ int semi;semi=SEM get(MYKEY,1,IPC _ CREAT | 0666);//创建了一个权限为666的信号量printf(' semi=% d \ n 'semi);return0}运行结果是:
我们可以使用IPCS s来查看它是否创建成功。
使用ipcrm-ssemid number删除指定的信号量。
需要C/C++Linux服务器架构师学习资料私信“资料”(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
=========================================================================
格式:
# includes ys/SEM . hintsemctl(int _ semid,int_semnum,int _ cmd……);功能:控制信号量的信息。
返回值:0表示成功,-1表示失败;
参数:
_ semid信号量的标识代码(ID ),它是semget()函数的返回值;
_semnum,信号集中操作信号的编号。从0开始。
_cmd命令,指示要执行的操作。
下面列出的命令来自百度!
可以在参数cmd中使用的命令如下:
IPC_STAT读取信号量集的数据结构semid_ds,并将其存储在semun中的buf参数中。
IPC_SET设置信号量集的数据结构semid_ds中的ipc_perm,其值取自semun中的buf参数。
IPC_RMID从内存中删除信号量集。
GETALL用于读取信号量集中所有信号量的值。
GETNCNT返回等待资源的进程数。
GETPID返回执行semop操作的最后一个进程的PID。
GETVAL返回信号量集中单个信号量的值。
GETZCNT返回等待完全释放资源的进程数。
SETALL设置信号量集中所有信号量的值。
SETVAL设置信号量集中单个信号量的值。
Semunion第四个参数是可选的;Semunion:就是unionsemun的一个例子。
unionsemun { intvalstructsemid _ ds * bufunsignedshort * arrary};//下面是初始化信号量的代码。unionsemunsem _ argsunsignedshortarray[1]={ 1 };sem _ args.array=arrayret=SEM CTL(semi,0,SETALL,SEM _ args);//0表示一个信号量的初始化,即有一个资源if(-1==ret){per。
ror("semctl");exit(EXIT_FAILURE);}=========================================================================
格式:
#includeintsemop(intsemid,structsembuf*_sops,size_t_nsops); 功能:用户改变信号量的值。也就是使用资源还是释放资源使用权。
返回值:成功返回0,失败返回-1;
参数:
_semid:信号量的标识码。也就是semget()的返回值。
_sops是一个指向结构体数组的指针。
structsembuf{unsignedshortsem_num;//第几个信号量,第一个信号量为0;shortsem_op;//对该信号量的操作。short_semflg;};sem_num:操作信号在信号集中的编号。第一个信号的编号为0;
sem_op:如果其值为正数,该值会加到现有的信号内含值中。通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值。通常用于获取资源的使用权;如果sem_op的值为0,则操作将暂时阻塞,直到信号的值变为0。
_semflgIPC_NOWAIT//对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。
IPC_UNDO//程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
nsops:操作结构的数量,恒大于或等于1。
下面看个例子:
源文件1:
#include#include#include#include#include#include#defineSEM_KEY6666unionsemun{intsetval;structsemid_ds*buf;unsignedshort*array;};intmain(intargc,char*argv[]){intshmid;float*addr;floath,w;shmid=shmget(ftok(".",1000),getpagesize(),IPC_CREAT|0666);//创建一个共享内存,权限为0666printf("shmid=%d\n",shmid);if(shmid==-1){perror("shmgeterror:");exit(EXIT_FAILURE);}addr=shmat(shmid,0,0);//获取共享内存的起始地址,且为可读可写if(-1==*addr){perror("shmaterror:");exit(EXIT_FAILURE);}intsemid;intret;semid=semget(SEM_KEY,2,IPC_CREAT|0600);//创建2个信号量if(-1==semid){perror("semget");exit(EXIT_FAILURE);}printf("semid=%d\n",semid);//初始化2个信号量unionsemunsem_args;unsignedshortarray[2]={1,1};sem_args.array=array;ret=semctl(semid,1,SETALL,sem_args);//SETALL代表设置信号集中所有的信号量的值。1,代表2个,sem_args是具体初始化的值放在共用体中。if(-1==ret){perror("semctl");exit(EXIT_FAILURE);}//对资源的使用处理操作structsembufsem_opt_wait1[1]={0,-1,SEM_UNDO};structsembufsem_opt_wakeup1[1]={0,1,SEM_UNDO};structsembufsem_opt_wait2[1]={1,-1,SEM_UNDO};structsembufsem_opt_wakeup2[1]={1,1,SEM_UNDO};while(1){semop(semid,sem_opt_wait2,1);//获取进程2的资源,让进程2等待printf("enteryouheight(CM)andheight(KG):\n");scanf("%f%f",addr,addr+1);semop(semid,sem_opt_wakeup1,1);//唤醒进程1,即释放资源的使用权if(*addr==1||*(addr+1)==1)break;//如果输入身高是1或体重是1就退出}return0;} 源程序2:
#include#include#include#include#include#include#include#defineSEM_KEY6666unionsemun{intsetval;structsemid_ds*buf;unsignedshort*array;};intmain(intargc,char*argv[]){intshmid;float*addr;floath,w;shmid=shmget(ftok(".",1000),getpagesize(),IPC_CREAT|0666);//打开刚才原程序1创建的共享内存,权限为0666printf("shmid=%d\n",shmid);if(shmid==-1){perror("shmgeterror:");exit(EXIT_FAILURE);}addr=shmat(shmid,0,0);//获取共享内存的起始地址,且为可读可写if(-1==*addr){perror("shmaterror:");exit(EXIT_FAILURE);}intsemid;intret;semid=semget(SEM_KEY,0,IPC_CREAT|0600););//取得信号量if(-1==semid){perror("semget");exit(EXIT_FAILURE);}printf("semid=%d\n",semid);//对资源的使用处理操作structsembufsem_opt_wait1[1]={0,-1,SEM_UNDO};structsembufsem_opt_wakeup1[1]={0,1,SEM_UNDO};structsembufsem_opt_wait2[1]={1,-1,SEM_UNDO};structsembufsem_opt_wakeup2[1]={1,1,SEM_UNDO};while(1){semop(semid,sem_opt_wait1,1);//获取进程1的资源好让进程1等待。h=*addr;w=*(addr+1);printf("h=%f\tw=%f\n",h,w);if(h==1.0||w==1.0)break;;//如果输入身高是1或体重是1就退出intret=w/(h*h/10000);if(ret>=20&&ret<=25){printf("ok!\n");}elseif(ret<20){printf("thin!\n");}else{printf("fat!\n");}semop(semid,sem_opt_wakeup2,1);//释放进程2的资源,即唤醒进程2}if(-1==semctl(semid,1,IPC_RMID,0))//删除信号量{perror("semctlerror:");exit(EXIT_FAILURE);}if(-1==shmdt(addr))//释放共享内存,使其不再有任何指向它的指针{perror("shmdterror:");exit(EXIT_FAILURE);}if(shmctl(shmid,IPC_RMID,0)==-1)//删除共享内存{perror("shctlerror:");exit(EXIT_FAILURE);}return0;}//两个进程相互制约,而达到资源的有效使用。 运行结果:
上一篇:正月十五什么时候开灯?