目录1. 信号量和P、V原语2. 信号量操作接口3. 封装Sem1. 信号量和 P、V 原语信号量和P、V原语由Dijkstra迪杰斯特拉提出。1.1 信号量常规理解执行流间互斥与同步。1.2 信号量值含义S 0S表示可用资源的个数。S 0表示无可用资源、无等待进程。S 0|S|表示等待队列中的进程个数。1.3 信号量结构体伪代码// 信号量本质上是一个计数器 struct semaphore { int value; pointer_PCB queue; };1.4 P 原语P(s) { s.value--; if (s.value 0) { // 将该进程状态置为等待状态 // 将该进程的 PCB 插入相应等待队列 s.queue 的末尾 } }1.5 V 原语V(s) { s.value; if (s.value 0) { // 唤醒相应等待队列 s.queue 中等待的一个进程 // 改变其状态为就绪态 // 将其插入 OS 就绪队列 } }1.6 信号量集结构体Thesemid_dsdata structure is defined insys/sem.has follows:structsemid_ds{structipc_permsem_perm;/* Ownership and permissions */time_tsem_otime;/* Last semop time */time_tsem_ctime;/* Last change time */unsignedlongsem_nsems;/* No. of semaphores in set */};Theipc_permstructure is defined as follows (the fieldsuid,gid, andmodeare settable usingIPC_SET):structipc_perm{key_t__key;/* Key supplied to semget(2) */uid_tuid;/* Effective UID of owner */gid_tgid;/* Effective GID of owner */uid_tcuid;/* Effective UID of creator */gid_tcgid;/* Effective GID of creator */unsignedshortmode;/* Permissions */unsignedshort__seq;/* Sequence number */};2. 信号量操作接口2.1 semgetNAMEsemget- get a System V semaphore set identifierSYNOPSIS#includesys/types.h#includesys/ipc.h#includesys/sem.hintsemget(key_tkey,intnsems,intsemflg);RETURN VALUEIf successful, the return value will be thesemaphore set identifier(a nonnegative integer), otherwise,-1is returned, witherrnoindicating the error.参数介绍key信号量集的键值同消息队列和共享内存。nsems信号量集中信号量的个数。semflg同消息队列和共享内存。2.2 semctlNAMEsemctl- System V semaphore control operationsSYNOPSIS#includesys/types.h#includesys/ipc.h#includesys/sem.hintsemctl(intsemid,intsemnum,intcmd,...);This function has three or four arguments, depending oncmd. When there are four, the fourth has the typeunion semun.The calling program must define this union as follows:unionsemun{intval;/* Value for SETVAL */structsemid_ds*buf;/* Buffer for IPC_STAT, IPC_SET */unsignedshort*array;/* Array for GETALL, SETALL */structseminfo*__buf;/* Buffer for IPC_INFO (Linux-specific) */};RETURN VALUEOn failure,semctl()returns-1witherrnoindicating the error.Otherwise, the system call returns a nonnegative value depending oncmdas follows:GETNCNT: the value ofsemncnt.GETPID: the value ofsempid.GETVAL: the value ofsemval.GETZCNT: the value ofsemzcnt.IPC_INFO: the index of the highest used entry in the kernel’s internal array recording information about all semaphore sets. This information can be used with repeatedSEM_STATorSEM_STAT_ANYoperations to obtain information about all semaphore sets on the system.SEM_INFO: as forIPC_INFO.SEM_STAT: the identifier of the semaphore set whose index was given insemid.SEM_STAT_ANY: as forSEM_STAT.All othercmdvalues return0on success.参数介绍semid由semget返回的信号集标识码。semnum信号集中信号量的序号。semctl()performs the control operation specified bycmdon the System V semaphore set identified bysemid, or onthesemnum-th semaphore of that set. The semaphores in a set are numberedstarting at0.cmd将要采取的动作具体动作查看man手册。2.3 semopNAMEsemop,semtimedop- System V semaphore operationsSYNOPSIS#includesys/types.h#includesys/ipc.h#includesys/sem.hintsemop(intsemid,structsembuf*sops,size_tnsops);semop()performs operations on selected semaphores in the set indicated bysemid. Each of thensopselements in the array pointed to bysopsis a structure that specifies an operation to be performed on a single semaphore.The elements of this structure are of typestruct sembuf, containing the following members:unsignedshortsem_num;/* semaphore number */shortsem_op;/* semaphore operation: -1, P 操作; 1, V 操作 */shortsem_flg;/* operation flags */Flags recognized insem_flgareIPC_NOWAITandSEM_UNDO.If an operation specifiesSEM_UNDO, it will be automatically undone when the process terminates.RETURN VALUEIf successful,semop()andsemtimedop()return0; otherwise they return-1witherrnoindicating the error.参数介绍semid该信号量的标识码也就是semget函数的返回值。sops指向一个sembuf结构的指针。nsopssops数组中的操作项数量可在一次semop调用中提交多个操作。3. 封装 Sem我们使用信号量简化信号量使用测试使用二元信号量对显示输出进行互斥打印。3.1 Sem.hpp#pragmaonce#includeiostream#includestring#includememory#includecstdlib#includesys/types.h#includesys/ipc.h#includesys/sem.h#includeunistd.hconststd::string pathname/tmp;intproj_id0x77;#defineGET_SEMIPC_CREAT// 不给权限#defineBUILD_SEM(IPC_CREAT|IPC_EXCL|0666)// 只关注使用和删除classSemaphore{public:Semaphore(intsemid,intflag):_semid(semid),_flag(flag){}voidP(){structsembufsb;// 该结构系统提供sb.sem_num0;sb.sem_op-1;sb.sem_flgSEM_UNDO;intn::semop(_semid,sb,1);(void)n;}voidV(){structsembufsb;sb.sem_num0;sb.sem_op1;sb.sem_flgSEM_UNDO;intn::semop(_semid,sb,1);(void)n;}~Semaphore(){if(_flagGET_SEM)return;// 让信号量自动销毁// 如果销毁信号量集合The argument semnum is ignoredintn::semctl(_semid,0,IPC_RMID);(void)n;std::coutsem set destroy!std::endl;}private:int_semid;int_flag;};usingsem_sptrstd::shared_ptrSemaphore;// 使用简单的建造者模式用它来构建单 semclassSemaphoreBuilder{public:SemaphoreBuilder():_val(-1){}SemaphoreBuilderSetVal(intval){_valval;return*this;// 支持连续访问}sem_sptrBuild(intflag){// 0. 先做简单的合法性判断if(_val0){std::cerryou must init first!std::endl;returnnullptr;}// 1. 申请 key 值key_t k::ftok(pathname.c_str(),proj_id);if(k0)std::exit(1);// 2. 根据初始值创建信号量集合intsemid::semget(k,1,flag);// 只创建一个信号量就够用了if(semid0)std::exit(2);if(BUILD_SEMflag){// 3. 初始化信号量unionsemun// 该联合体系统不提供需要我们自己定义{intval;/* Value for SETVAL */structsemid_ds*buf;/* Buffer for IPC_STAT, IPC_SET */unsignedshort*array;/* Array for GETALL, SETALL */structseminfo*__buf;/* Buffer for IPC_INFO (Linux-specific) */}un;un.val_val;// 设置为初始值intn::semctl(semid,0,SETVAL,un);if(n0)std::exit(3);}// 4. 创建并返回信号量集合returnstd::make_sharedSemaphore(semid,flag);}~SemaphoreBuilder(){}private:int_val;// 所有信号量的初始值};3.2 Writer.cc测试信号量接口#includeSem.hpp#includecstdio#includecstdlib#includetime.h#includeunistd.hintmain(){SemaphoreBuilder sb;autofsemsb.SetVal(1).Build(BUILD_SEM);// 创建一个信号量并初始化为 1当作锁使用if(fork()0){autocsemsb.Build(GET_SEM);intcnt10;while(cnt--){csem-P();printf(C);fflush(stdout);usleep(std::rand()%95270);printf(C );usleep(std::rand()%43990);fflush(stdout);csem-V();}std::exit(0);}intcnt50;while(cnt--){fsem-P();printf(F);fflush(stdout);usleep(std::rand()%95270);printf(F );usleep(std::rand()%43990);fflush(stdout);fsem-V();}return0;}3.3 结论System V信号量生命周期也是随内核的。ipcs -s ipcrm -s semid3.4 关于建造者模式
阅读完成 · 觉得有帮助?