Linux下的信号量

时间:2021-08-04 05:28:16

linux下的信号量本身就是临界资源,所以PV操作都是原子操作。

下面是实现二元信号量的代码,二元信号量就是互斥锁。

信号量代码中的semop函数是进行PV操作的核心函数,semop的函数原型为:

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

第一个参数semid为获得的信号量集标识符,第二个参数是一个指向定义的结构体的指针,第三个参数是信号量的个数。

semid由semget获得;

定义的结构体为:

struct sembuf

{

unsigned short sem_num; /* semaphore number */   sem_num是将信号量集视为一个数组的数组下标,第一个信                                                     号量下标为0

short sem_op; /* semaphore operation */          op决定是P操作还是V操作,P操作为-1(信号量-1),V操                                                     作为1(信号量+1)

short sem_flg; /* operation flags */             flags有多个选项

};

flags:

IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息。

SEM_UNDO //程序结束时(不论正常或不正常),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。

如果父进程在进行了P操作后异常退出,SEM_UNDO可以保证子进程不用一直等待父进程的V操作,避免死锁。

       0 // 缺省

在二元信号量中我们一般将flags设为SEM_UNDO,防止出现死锁问题。

comm.h

  1 #ifndef _COMM_H_
2 #define _COMM_H_
3
4 #include<stdio.h>
5 #include<sys/types.h>
6 #include<sys/ipc.h>
7 #include<sys/sem.h>
8 #include<stdlib.h>
9
10 #define PATHNAME "."
11 #define PROJ_ID 0x6666
12
13 int creat(int nums);
14 int get(int nums);
15 int destory(int semid);
16 int init(int semid,int nums,int initval);
17 int P(int semid,int which);
18 int V(int semid,int which);
19 union semun{
20 int val;
21 struct semid_ds *buf;
22 unsigned short *arrary;
23 struct semiofo *_buf;
24 };
25
26 #endif

comm.c

  1 #include"comm.h"
2
3
4 static int com(int nums,int flags)
5 {
6 key_t key=ftok(PATHNAME,PROJ_ID);
7 if(key<0)
8 {
9 perror("ftok");
10 return -1;
11 }
12 int semid=semget(key,nums,flags);
13 if(semid<0)
14 {
15 perror("semid");
16 return -2;
17 }
18 return semid;
19 }
20
21 int creat(int nums)
22 {
23 return com( nums,IPC_CREAT|IPC_EXCL|0666);
24 }
25
26 int get(int nums)
27 {
28 return com(nums,IPC_CREAT);
29 }
30
31 int destory(int semid)
32 {
33 if(semctl(semid,0,IPC_RMID)<0)
34 {
35 perror("semctl");
36 return -1;
37 }
38 return 0;
39 }
40
41 int init(int semid,int nums,int initval)
42 {
43 union semun un;
44 un.val=initval;
45 if(semctl(semid,nums,SETVAL,un)<0)
46 {
47 perror("semctl");
48 return -1;
49 }
50 return 0;
51 }
52
53 static int sempv(int semid,int which,int op)
54 {
55 struct sembuf _sf;
56 _sf.sem_num=which;
57 _sf.sem_op=op;
57 _sf.sem_op=op;
58 _sf.sem_flg=SEM_UNDO;
59 if(semop(semid,&_sf,1)<0)
60 {
61 perror("semop");
62 return -1;
63 }
64 return 0;
65 }
66
67 int P(int semid,int which)
68 {
69 return sempv(semid,which,-1);
70 }
71 int V(int semid,int which)
72 {
73 return sempv(semid,which,1);
74 }


sem.c

  1 #include"comm.h"
2
3 int main()
4 {
5 int semid=creat(1);
6 init(semid,0,1);
7 pid_t id=fork();
8 if(id==0)
9 {//child
10 int _semid=get(0);
11 while(1)
12 {
13 P(_semid,0);
14 printf("A");
15 fflush(stdout);
16 usleep(300000);
17 printf("A");
18 fflush(stdout);
19 usleep(623456);
20 V(_semid,0);
21 }
22 } else
23 {//father //我们选择让AB成对出现,保证每个进程都有PV操作
24 while(1)
25 {
26 P(semid,0);
27 usleep(100000);
28 printf("B");
29 fflush(stdout);
30 usleep(400000);
31 printf("B");
32 fflush(stdout);
33 usleep(200000);
34 V(semid,0);
35 }
36 pid_t ret=waitpid(id,NULL,0);
37 if(ret<0)
38 {
39 printf("wait success!\n");
40 }
41 }
42 return 0;
43 }

Linux下的信号量

Linux下的信号量