信号量与简单互斥锁的实现
信号量:与管道和消息队列不同,信号量可以说是一个计数器,它用来控制多进程对临界资源的访问,它作的是PV操作,P为减一操作,它是用来获取临界资源的使用权,如果减一之后大于零则可以访问,不然就挂起等待,V为加一操作,当进程对他的访问结束后便执行,用来归还资源的使用权。
原子操作:PV的加一减一都是原子操作也就是说加一减一对应的计算机语言只有一条操作,如果不这样设计就会引起双方同时的申请导致不能正常执行。
int semget(key_t key, int nsems, int semflg);
这是信号量的获取函数,nsmes表示要申请的信号量集的个数,另外两个都很熟悉了。
The semid_ds data structure is defined in <sys/sem.h> as follows:
struct semid_ds {
struct ipc_perm sem_perm; /* Ownership and permissions */
time_t sem_otime; /* Last semop time */
time_t sem_ctime; /* Last change time */
unsigned short sem_nsems; /* No. of semaphores in set */
};
上面是计算机内核为每个信号量集设计的一个结构体。每个信号量
int semop(int semid, struct sembuf *sops, unsigned nsops);
这个函数就是用来执行PV操作的函数,
struct sembuf{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};//这个结构体是用来操作每一个信号所使用的一个结构,sem_num表示
要操作的是第几个信号(数组下标),sem_op表示执行PV操作中的哪一种。
*sem_flg();它是semop中sembuf结构体的一个对象,它的作用是用来选择一种执行方式的
有0阻塞式等待,IPC_NOWAIT(非阻塞式等待),SEM_UNDO(如它的名字一样什么也不做,在这个进程执行的所有PV操作在这个进程结束后信号量的值都还原为刚进入这个进程时的值,避免此进程出错)
信号量实现一个互斥锁的代码
对比可以看出由于进程间的互斥访问输出,没有ab的交错
comm.c
1 #include"comm.h"
2 union semun {
3 int val; /* Value for SETVAL */
4 struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
5 unsigned short *array; /* Array for GETALL, SETALL */
6 struct seminfo *__buf; /* Buffer for IPC_INFO*/
7 };
8
9 static int comm_get_sem(int msems,int flag)
10 {
11 key_t _sem_key=ftok(_PATH_,_PROJ_ID);
12 if(_sem_key<0)
13 {
14 perror("ftok");
15 return -1;
16 }
17 int sem_id=semget(_sem_key,msems,flag);
18 if(sem_id<0)
19 {
20 return -1;
21 }
22 return sem_id;
23
24 }
25 int creat_sem(int nsems)
26 {
27 umask(0);
28 return comm_get_sem(nsems,IPC_CREAT|IPC_EXCL|0666);
29 }
30
31 int get_sem()
32 {
33 return comm_get_sem(0,IPC_CREAT);
34 }
35 int init_sem(int semid,int whitch)
36 {
37 union semun _semnu;
38 _semnu.val=1;
39 int ret = semctl(semid,whitch,SETVAL,_semnu);
40 return ret;
41 }
42 static int sem_op(int semid,struct sembuf *sops,unsigned nsops)
43 {
44 return semop(semid,sops,nsops);
45 }
46 int p_sem_op(int semid,int which)
47 {
48 struct sembuf sem;
49 sem.sem_op=-1;
50 sem.sem_num=which;
51 sem.sem_flg=SEM_UNDO;
52 return sem_op(semid,&sem,1);
53 }
54
55 int v_sem_op(int semid,int which)
56 {
57 struct sembuf sem;
58 sem.sem_op=1;
59 sem.sem_num=which;
60 sem.sem_flg=SEM_UNDO;
61 return sem_op(semid,&sem,1);
62 }
63 int destroy_sem(int sem_id)
64 {
65 int ret =semctl(sem_id,0,IPC_RMID,NULL);
66
67 if(ret <0){
68 return -1;
69 }
70 return 0;
71 }
sem_socket.c
1 #include"comm.h"
2
3 int main()
4 {
5 int sem_id=creat_sem(1);
6 int ret=init_sem(sem_id,0);
7 pid_t id=fork();
8 if(id<0)
9 {
10 perror("fork");
11 }else if(id==0){
12 int sem_id=get_sem();
13 while(1){
14 // printf("child begin:\n");
15 p_sem_op(sem_id,0);
16 printf("A");
17 fflush(stdout);
18 sleep(2);
19 printf("A");
20 fflush(stdout);
21 sleep(1);
22 v_sem_op(sem_id,0);
23 }
24 }else{
25 while(1)
26 {
27 //sleep(10);
28 p_sem_op(sem_id,0);
29 printf("B");
30 fflush(stdout);
31 sleep(1);
32 printf("B");
33 fflush(stdout);
34 sleep(2);
35 v_sem_op(sem_id,0);
36 }
37 waitpid(id,0,NULL);
38 }
39
40
41 return 0;
42 }
"sem_socket.c" 42L, 588C 1,1 顶端
本文出自 “痕迹” 博客,请务必保留此出处http://wpfbcr.blog.51cto.com/10696766/1763929