源码先锋

源码先锋

Linux信号量详解

admin 30 195

信号量

1、信号量和P、V原语

信号量和P、V原语由迪杰斯特拉提出

互斥:P、V在同一个进程中

同步:P、V在不同进程中

信号量值含义:

(1)S0:S表示可用资源的个数。

(2)S=0:表示无可用资源,无等待进程。

(3)S0:|S|表示等待队列中进程个数。

P原语:

P(s){=;if(){//该进程状态置为等待状态//将该进程的PCB插入相应的等待队列末尾}}

V原语:

V(s){=++;if(=0){//唤醒相应等待队列中等待的一个进程//改变其状态为就绪态,并将其插入就绪队列}}

2、信号量集函数

//(1)semget函数//功能:用来创建和访问一个信号量集//原型:intsemget(key_tkey,intnsems,intsemflg);//参数:key:信号集的名字//nsems:信号集中信号量的个数//semflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的//返回值:成功返回0,失败返回-1//(2)shmctl函数//功能:用于控制信号量集//原型:intsemctl(intsemid,intsemnum,intcmd,);//参数:semid:由semget返回的信号集标识码//semnum:信号集中信号量的个数//cmd:将要采取的动作(有三个可取值)//最后一个参数根据不同而不同//返回值:成功返回0,失败返回-1//(3)semop函数//功能:用来创建和访问一个信号量集//原型:intsemop(intsemid,structsembuf*sops,unsignednsops);//参数://semid:是该信号量的标识码//sops:是个指向一个结构数值的指针//nsops:信号量个数//返回值:成功返回0,失败返回-1

3、实例代码

注:

sembuf结构体

structsembuf{shortsem_num;//信号量的编号shortsem_op;//是信号量一次PV操作时加减的数值,一般只会有两个-1(P操作)或+1(V操作)shortsem_flg;//有两个取值是IPC_NOWAIT或SEM_UNDO}
//【】define_COMM_H__includeincludedefinePROJ_ID0x6666unionsemun{intval;structsemid_ds*buf;unsignedshort*array;structseminfo*_buf;};intcreateSemSet(intnums);intinitSem(intsemid,intnums,intinitval);intgetSemSet(intnums);intP(intsemid,intwho);intV(intsemid,intwho);intdestorySemSet(intsemid);include""staticintcommSemSet(intnums,intflags){key_t_key=ftok(PATHNAME,PROJ_ID);if(_key0){perror("ftok");return-1;}intsemid=semget(_key,nums,flags);if(semid0){perror("semget");return-2;}returnsemid;}intcreateSemSet(intnums){returncommSemSet(nums,IPC_CREAT|IPC_EXCL|0666);}intgetSemSet(intnums){returncommSemSet(nums,IPC_CREAT);}intinitSem(intsemid,intnums,intinitval){unionsemun_un;_=initval;if(semctl(semid,nums,SETVAL,_un)0){perror("semctl");return-1;}return0;}staticintcommPV(intsemid,intwho,intop){structsembuf_sf;__num=who;__op=op;__flg=0;if(semop(semid,_sf,1)0){perror("semop");return-1;}return0;}intP(intsemid,intwho){returncommPV(semid,who,-1);}intV(intsemid,intwho){returncommPV(semid,who,1);}intdestorySemSet(intsemid){if(semctl(semid,0,IPC_RMID)0){perror("semctl");return-1;}return0;}//【sem_】#include""intmain(){intsemid=createSemSet(1);printf("se=%d\n",semid);initSem(semid,0,1);pid_tid=fork();if(id==0){//childint_semid=getSemSet(0);printf("_semid=%d\n",_semid);while(1){P(_semid,0);printf("A");fflush(stdout);usleep(200000);printf("A");fflush(stdout);usleep(200000);V(_semid,0);}}else{//fatherwhile(1){P(semid,0);printf("B");fflush(stdout);usleep(200000);printf("B");fflush(stdout);usleep(200000);V(semid,0);}wait(NULL);}destorySemSet(semid);return0;}

运行结果:

将封装成静态库:

[lize-h@localhost0406_SignalNum]$_[lize-h@localhost0406_SignalNum]$[lize-h@localhost0406_SignalNum]$_生成静态库:[lize-h@localhost0406_SignalNum]$是gnu归档工具,rc表示(replaceandcreate)[lize-h@localhost0406_SignalNum]$/5001676May421:162018:列出静态库中的文件v:verbose详细信息在不调用静态库的情况下编译失败[lize-h@localhost0406_SignalNum]$gcctest_/tmp/:Infunction`main':test_:(.text+0x11):undefinedreferenceto`createSemSet'test_:(.text+0x46):undefinedreferenceto`initSem'test_:(.text+0x66):undefinedreferenceto`getSemSet'test_:(.text+0x93):undefinedreferenceto`P'test_:(.text+0xf2):undefinedreferenceto`V'test_:(.text+0x108):undefinedreferenceto`P'test_:(.text+0x167):undefinedreferenceto`V'collect2:ld返回1调用静态库[lize-h@localhost0406_SignalNum]$gcctest_-lmycomm-ocomm-L:指定库路径-l:指定库名测试目标文件生成后,删除静态库程序照样可以运行[lize-h@localhost0406_SignalNum]$_

将封装成动态库:

[lize-h@localhost0406_SignalNum]$_:表示生成共享库fPIC:产生位置无关码[lize-h@localhost0406_SignalNum]$[lize-h@localhost0406_SignalNum]$*.o[lize-h@localhost0406_SignalNum]$_调用动态库进行编译[lize-h@localhost0406_SignalNum]$gcctest_-lmycomm[lize-h@localhost0406_SignalNum]$_[lize-h@localhost0406_SignalNum]$./=131074B_semid=131074BAABBA^C[lize-h@localhost0406_SignalNum]$//可以将.so文件拷贝到系统共享库路径下,通常为/usr/lib将.so文件放到系统共享路径下调用时更简单[lize-h@localhost0406_SignalNum]$gcctest_