先了解几个概念:
临界资源:在一段时间内只允许一个进程访问的资源。
临界区:每个进程中访问临界资源的那段代码称为临界区。
进程互斥:两个或两个以上进程不能同时访问临界资源。
进程同步:异步环境下一组并发进程因相互制约关系而有序的执行。
信号量:对外部资源的一种标识,来表示某种资源是否可用。相当于一种特殊的×××量(原子操作),当请求某种资源时,先判断此资源是否可用,如果可用,则向系统申请该资源,即进行P操作(-1操作),用完该资源后,归还资源,即进行V操作(+1)。
通常信号量在系统中是以信号量集的方式创建,即用多个信号量来表示系统中多个资源的可用情况。
其生命周期随内核。
函数:
int semget(key_t key,int nsems,int semflag); //创建信号量
int semctl(int semid,int semnum,int cmd ...); //删除该信号量
int semop(int semid,struct sembuf *sops,unsigned nsops);//P、V操作
该信号量是SYSTEM版本的
下面的代码为了更好的体现互斥性,所以只创建了一个信号量。
comm.h 1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/types.h> 4 #include<sys/ipc.h> 5 #include<sys/sem.h> 6 #define _PATH_ "." 7 #define _PROJ_ID_ 0x6666 8 9 union semun 10 { 11 int val; 12 struct semid_ds *buf; 13 unsigned short *array; 14 struct seminfo *__buf; 15 }; 16 int creat_sem(int sem_nums); 17 int get_sem(int sem_nums); 18 int init_sem(int sem_id,int sem_num,int init_val); 19 int p_sem(int sem_id,int sem_num); 20 int v_sem(int sem_id,int sem_num); 21 int distroy_sem(int sem_id); comm.c 1 #include"comm.h" 2 3 static int comm_creat_sem(int flags,int sem_nums) 4 { 5 key_t _key = ftok(_PATH_,_PROJ_ID_); 6 if(_key == -1) 7 { 8 perror("ftok"); 9 return -1; 10 } 11 int sem_id = semget(_key,sem_nums,flags); 12 if(sem_id==-1) 13 { 14 perror("semget"); 15 return -1; 16 } 17 return sem_id; 18 } 19 int creat_sem(int sem_nums) 20 { 21 int flags = IPC_CREAT|IPC_EXCL|0666; 22 return comm_creat_sem(flags,sem_nums); 23 } 24 int get_sem(int sem_nums) 25 { 26 int flags = IPC_CREAT; 27 return comm_creat_sem(flags,sem_nums); 28 29 } 30 int init_sem(int sem_id,int sem_num,int init_val) 31 { 32 union semun un; 33 un.val = init_val; 34 if(semctl(sem_id,sem_num,SETVAL,un,NULL)==-1) 35 { 36 perror("semctl"); 37 return -1; 38 } 39 return 0; 40 } 41 static int op_sem(int sem_id,int sem_num,int op) 42 { 43 struct sembuf sem[1]; 44 sem[0].sem_num = sem_num; 45 sem[0].sem_op = op; 46 sem[0].sem_flg = 0; 47 if(semop(sem_id,&sem[0],1)==-1) 48 { 49 perror("semop"); 50 return -1; 51 } 52 return 0; 53 } 54 int p_sem(int sem_id,int sem_num) 55 { 56 return op_sem(sem_id,sem_num,-1); 57 } 58 int v_sem(int sem_id,int sem_num) 59 { 60 return op_sem(sem_id,sem_num,1); 61 } 62 int distroy_sem(int sem_id) 63 { 64 if(semctl(sem_id,0,IPC_RMID,NULL)==-1) 65 { 66 perror("semctl"); 67 return -1; 68 } 69 return 0; 70 } test.c 1 #include"comm.h" 2 #include<unistd.h> 3 #include<stdlib.h> 4 int main() 5 { 6 int sem_id = creat_sem(1); 7 if(sem_id==-1) 8 { 9 return -1; 10 } 11 init_sem(sem_id,0,1); 12 pid_t id = fork(); 13 if(id<0) 14 { 15 perror("fork"); 16 exit(1); 17 } 18 else if(id == 0) 19 { 20 int sem_id = get_sem(0); 21 while(1) 22 { 23 p_sem(sem_id,0); 24 25 printf("A"); 26 fflush(stdout); 27 sleep(1); 28 printf("A"); 29 fflush(stdout); 30 sleep(2); 31 32 v_sem(sem_id,0); 33 } 34 } 35 else 36 { 37 while(1) 38 { 39 p_sem(sem_id,0); 40 41 printf("B"); 42 fflush(stdout); 43 sleep(1); 44 printf("B"); 45 fflush(stdout); 46 sleep(3); 47 48 v_sem(sem_id,0); 49 } 50 waitpid(id,NULL,0); 51 distroy_sem(sem_id); 52 53 } 54 return 0; 55 } 结果: //不加信号量:(由于对临界资源(显示屏)的竞争,打印结果出现是交叉的) [fbl@localhost sem]$ ./test BABAABABAABBAABABAABABAABBAABABAABABAA^C //加入信号量: [fbl@localhost sem]$ ./test BBAABBAABBAABBAABBA^C
静态库打包:
Makefile: 1 libmysem.a:comm.o 2 ar rcs $@ $^ 3 comm.o:comm.c 4 gcc -c $< 5 .PHONY:clean 6 clean: 7 rm -rf libmysem.a comm.o output 8 .PHONY:output 9 output: 10 mkdir output 11 cp libmysem.a output 12 cp comm.h output 13