信号量:相当于一个计数器,计录当前环境某种资源个数。没有对信号进行传输,保证对信号量操作是原子的。主要为了保护临界资源。生命周期随内核。

临界区:访问共享资源的代码区

临界资源:进程间所共享的资源

互斥:同一时刻,只允许一个进程对这份资源访问,这个进程对资源具有独占性,排他性。

同步:互斥情况下,进程对临界资源访问具有顺序。

信号量有两个基本操作:P,V

p:减一,向信号量申请资源,申请到后若p=0,则将进程挂起,否则信号量减一。

v:加一,使用资源完毕,归还给系统,若有进程挂起,则唤醒等待进程或线程,否则将信号量加一。

使用到的主要函数原型:

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

int semctl(int semid, int semnum, int cmd, ...);

int semop(int semid, struct sembuf *sops, unsigned nsops);

union semun {

int val; /* Value for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

unsigned short *array; /* Array for GETALL, SETALL */

struct seminfo *__buf; /* Buffer for IPC_INFO

(Linux-specific) */

};

struct sembuf{

unsigned short sem_num; /* semaphore number */

short sem_op; /* semaphore operation */

short sem_flg; /* operation flags */

}中sem_flg表示以什么形式控制信号量,0表示默认,SEM_NODO表示取消

注意:信号量的创建是以信号量集的形式创建

当semctl(semid,semnum,cmd);要删除时cmd被设置为IPC_RMID,semnum被忽视。当cmd为SETVAL时,对第semnum个信号量初始化。

信号量集中信号量从0开始

grep -ER 'semum' /usr/include/ 查询semum

//comm.h1#pragmaonce2#include<stdio.h>3#include<stdlib.h>4#include<unistd.h>5#include<sys/types.h>6#include<sys/ipc.h>7#include<sys/sem.h>8#define_PATH_"."9#define_PROJ_ID_0x888810unionsemun11{12intval;13structsemid_ds*buf;14unsignedshort*array;15structseminfo*__buf;16};17//structsembuf18//{19//unsignedshortsem_num;20//shortsem_op;21//shortsem_flg;22//};23staticint_sem_set(intsnum,intflags);24staticintsem_op(intsem_id,intnsops,intflags);25intcreate_sem(intsnum);26intget_sem(intsnum);27intinit_sem(intsem_id,intsnum,intunit_val);28intsem_p_element(intsem_id,intnsops);29intsem_v_element(intsem_id,intnsops);30intdestory_sem_element(intsem_id);//comm.c1#include"comm.h"2staticint_sem_set(intsnum,intflags)3{4key_t_key=ftok(_PATH_,_PROJ_ID_);5if(_key<0)6{7perror("ftok");8return-1;9}10intsem_id=-1;11sem_id=semget(_key,snum,flags);12if(sem_id<0)13{1415perror("semget");16return-1;17}18returnsem_id;19}2021intcreate_sem(intsnum)22{23intflags=IPC_CREAT|IPC_EXCL|0666;24intret=_sem_set(snum,flags);25returnret;26}27intget_sem(intsnum)28{29return_sem_set(snum,IPC_CREAT);30}31intinit_sem(intsem_id,intsnum,intunit_val)32{33unionsemun_un;34_un.val=unit_val;35if(semctl(sem_id,snum,SETVAL,_un)<0)36{37perror("semctl\n");38return-1;39}40return0;41}42staticintsem_op(intsem_id,intseqnum,intop)43{44structsembuf_sm;45_sm.sem_num=seqnum;46_sm.sem_op=op;47_sm.sem_flg=0;48if(semop(sem_id,&_sm,1)<0)49{50perror("semop");51return-1;52}53return0;54}55intsem_p_element(intsem_id,intseqnum)56{57returnsem_op(sem_id,seqnum,-1);58}59intsem_v_element(intsem_id,intseqnum)60{61returnsem_op(sem_id,seqnum,1);62}63intdestory_sem_element(intsem_id)64{65if(semctl(sem_id,IPC_RMID,0,NULL)<0)66{67perror("semctl\n");68return-1;69}70return0;71}//test.c1#include"comm.h"2intmain()3{4intsem_id=create_sem(1);5if(sem_id<0)6{7printf("error\n");8return-1;9}10init_sem(sem_id,1,1);11pid_tpid=fork();12if(pid<0)13{14perror("pid");15return-1;16}17elseif(pid==0)18{19intsem_pid=get_sem(1);20while(1)21{22sem_p_element(sem_pid,0);23printf("A");24sleep(1);25fflush(stdout);26printf("A");27sleep(8);28fflush(stdout);29sem_v_element(sem_pid,0);30}31}32else33{34while(1)35{36sem_p_element(sem_id,0);37sleep(3);38printf("B");39sleep(2);40fflush(stdout);41printf("B");42sleep(5);43fflush(stdout);44sem_v_element(sem_id,0);45}46waitpid(pid,NULL,0);47destory_sem_element(sem_id);4849}50return0;51}//Makefile1.PHONY:all2all:test3test:test.ccomm.c4gcc-o$@$^5.PHONY:clean6clean:7rm-ftest

未使用信号量之前:

使用后: