信号量-济南IT培训负责整理
1、信号量和P、V原语
信号量和P、V原语由迪杰斯特拉提出
互斥:P、V在同一个进程中
同步:P、V在不同进程中
信号量值含义:
(1)S>0: S表示可用资源的个数.
(2)S=0:表示无可用资源,无等待进程.
(3)S<0: |S|表示等待队列中进程个数.
P原语:
P(s){s.value = s.value--;if(s.value < 0){//该进程状态置为等待状态//将该进程的PCB插入相应的等待队列s.queue末尾}}
V原语:
V(s){s.value = s.value++;if(s.value <= 0){//唤醒相应等待队列s.queue中等待的一个进程//改变其状态为就绪态,并将其插入就绪队列}}
2、信号量集函数
//(1)semget函数// 功能:用来创建和访问一个信号量集//原型:int semget(key_t key,int nsems,int semflg);//参数: key:信号集的名字// nsems:信号集中信号量的个数// semflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的//返回值:成功返回0,失败返回-1//(2)shmctl函数// 功能:用于控制信号量集//原型:int semctl(int semid,int semnum,int cmd, ...);//参数: semid:由semget返回的信号集标识码// semnum:信号集中信号量的个数// cmd:将要采取的动作(有三个可取值)// 最后一个参数根据不同而不同//返回值:成功返回0,失败返回-1//(3)semop函数//功能:用来创建和访问一个信号量集//原型:int semop(int semid,struct sembuf* sops,unsigned nsops);//参数:// semid:是该信号量的标识码// sops:是个指向一个结构数值的指针// nsops:信号量个数//返回值:成功返回0,失败返回-1
3、实例代码
注:
sembuf结构体
struct sembuf{short sem_num; //信号量的编号short sem_op; //是信号量一次PV操作时加减的数值,一般只会有两个 -1(P操作) 或 +1(V操作)short sem_flg; //有两个取值是IPC_NOWAIT或SEM_UNDO}
//【comm.h】#ifndef _COMM_H__#define _COMM_H__#include#include#include#include#define PATHNAME "."#define PROJ_ID 0x6666union semun{ int val; struct semid_ds* buf; unsigned short* array; struct seminfo* _buf;};int createSemSet(int nums);int initSem(int semid,int nums,int initval);int getSemSet(int nums);int P(int semid,int who);int V(int semid,int who);int destorySemSet(int semid);#endif//【comm.c】#include"comm.h"static int commSemSet(int nums,int flags){ key_t _key=ftok(PATHNAME,PROJ_ID); if(_key<0) { perror("ftok"); return -1; } int semid=semget(_key,nums,flags); if(semid<0) { perror("semget"); return -2; } return semid;}int createSemSet(int nums){ return commSemSet(nums,IPC_CREAT|IPC_EXCL|0666);}int getSemSet(int nums){ return commSemSet(nums,IPC_CREAT);}int initSem(int semid,int nums,int initval){ union semun _un; _un.val=initval; if(semctl(semid,nums,SETVAL,_un)<0) { perror("semctl"); return -1; } return 0;}static int commPV(int semid,int who,int op){ struct sembuf _sf; _sf.sem_num=who; _sf.sem_op=op; _sf.sem_flg=0; if(semop(semid,&_sf,1)<0) { perror("semop"); return -1; } return 0;}int P(int semid,int who){ return commPV(semid,who,-1);}int V(int semid,int who){ return commPV(semid,who,1);}int destorySemSet(int semid){ if(semctl(semid,0,IPC_RMID)<0) { perror("semctl"); return -1; } return 0;}//【sem_test.c】#include"comm.h"int main(){ int semid=createSemSet(1); printf("se=%d ",semid); initSem(semid,0,1); pid_t id=fork(); if(id==0) { //child int _semid=getSemSet(0); printf("_semid=%d ",_semid); while(1) { P(_semid,0); printf("A"); fflush(stdout); usleep(200000); printf("A "); fflush(stdout); usleep(200000); V(_semid,0); } } else { //father while(1) { P(semid,0); printf("B"); fflush(stdout); usleep(200000); printf("B "); fflush(stdout); usleep(200000); V(semid,0); } wait(NULL); } destorySemSet(semid); return 0;}
运行结果:
Linux信号量详解
将comm.c封装成静态库:
[lize-h@localhost 0406_SignalNum]$ lsa.out comm.c comm.h comm.o Makefile test_sem.c[lize-h@localhost 0406_SignalNum]$ gcc -c comm.c -o comm.o [lize-h@localhost 0406_SignalNum]$ lsa.out comm.c comm.h comm.o Makefile test_sem.c生成静态库:[lize-h@localhost 0406_SignalNum]$ ar -rc libmycomm.a comm.oar是gnu归档工具,rc表示(replace and create)[lize-h@localhost 0406_SignalNum]$ ar -tv libmycomm.arw-rw-r-- 500/500 1676 May 4 21:16 2018 comm.ot:列出静态库中的文件v:verbose详细信息在不调用静态库的情况下编译失败[lize-h@localhost 0406_SignalNum]$ gcc test_sem.c/tmp/ccvjqyzV.o: In function `main':test_sem.c:(.text+0x11): undefined reference to `createSemSet'test_sem.c:(.text+0x46): undefined reference to `initSem'test_sem.c:(.text+0x66): undefined reference to `getSemSet'test_sem.c:(.text+0x93): undefined reference to `P'test_sem.c:(.text+0xf2): undefined reference to `V'test_sem.c:(.text+0x108): undefined reference to `P'test_sem.c:(.text+0x167): undefined reference to `V'collect2: ld 返回 1调用静态库[lize-h@localhost 0406_SignalNum]$ gcc test_sem.c -L. -lmycomm -o comm-L :指定库路径-l :指定库名测试目标文件生成后,删除静态库程序照样可以运行[lize-h@localhost 0406_SignalNum]$ lscomm comm.c comm.h comm.o libmycomm.a Makefile test_sem.c
将comm.c封装成动态库:
[lize-h@localhost 0406_SignalNum]$ lscomm.c comm.h comm.o libmycomm.a Makefile test_sem.cshared:表示生成共享库fPIC:产生位置无关码[lize-h@localhost 0406_SignalNum]$ gcc -fPIC -c comm.c[lize-h@localhost 0406_SignalNum]$ gcc -shared -o libmycomm.so *.o[lize-h@localhost 0406_SignalNum]$ lscomm.c comm.h comm.o libmycomm.a libmycomm.so Makefile test_sem.c调用动态库进行编译[lize-h@localhost 0406_SignalNum]$ gcc test_sem.c -L. -lmycomm[lize-h@localhost 0406_SignalNum]$ lsa.out comm.c comm.h comm.o libmycomm.a libmycomm.so Makefile test_sem.c[lize-h@localhost 0406_SignalNum]$ ./a.outse=131074B_semid=131074B AA BB A^C[lize-h@localhost 0406_SignalNum]$//可以将 .so文件拷贝到系统共享库路径下,通常为 /usr/lib将.so文件放到系统共享路径下调用时更简单[lize-h@localhost 0406_SignalNum]$ gcc test_sem.c -lmycomm
更多济南IT培训相关咨询,请扫描下方二维码