您的位置:首页 > 其它

进程间通信之信号量

2016-04-15 13:18 375 查看
信号量:相当于一个计数器,计录当前环境某种资源个数。没有对信号进行传输,保证对信号量操作是原子的。主要为了保护临界资源。生命周期随内核。
临界区:访问共享资源的代码区
临界资源:进程间所共享的资源
互斥:同一时刻,只允许一个进程对这份资源访问,这个进程对资源具有独占性,排他性。
同步:互斥情况下,进程对临界资源访问具有顺序。
信号量有两个基本操作: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.h
1 #pragma once
2 #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_ 0x8888
10 union semun
11 {
12     int val;
13     struct semid_ds* buf;
14     unsigned short  *array;
15     struct seminfo  *__buf;
16 };
17 //struct sembuf
18 //{
19 //  unsigned short sem_num;
20 //  short sem_op;
21 //  short sem_flg;
22 // };
23 static int _sem_set(int snum,int flags);
24 static int sem_op(int sem_id,int nsops,int flags);
25 int create_sem(int snum);
26 int get_sem(int snum);
27 int init_sem(int sem_id,int snum,int unit_val);
28 int sem_p_element(int sem_id,int nsops);
29 int sem_v_element(int sem_id,int nsops);
30 int destory_sem_element(int sem_id);
//comm.c
1 #include"comm.h"
2 static int _sem_set(int snum,int flags)
3 {
4     key_t _key=ftok(_PATH_,_PROJ_ID_);
5     if(_key<0)
6     {
7         perror("ftok");
8         return -1;
9     }
10     int sem_id=-1;
11     sem_id=semget(_key,snum,flags);
12     if(sem_id<0)
13     {
14
15         perror("semget");
16         return -1;
17     }
18     return sem_id;
19 }
20
21 int create_sem(int snum)
22 {
23     int flags=IPC_CREAT|IPC_EXCL|0666;
24     int ret= _sem_set(snum,flags);
25     return ret;
26 }
27 int get_sem(int snum)
28 {
29     return _sem_set(snum,IPC_CREAT);
30 }
31 int init_sem(int sem_id,int snum,int unit_val)
32 {
33     union semun _un;
34     _un.val=unit_val;
35     if(semctl(sem_id,snum,SETVAL,_un)<0)
36     {
37             perror("semctl\n");
38         return -1;
39     }
40     return 0;
41 }
42 static int sem_op(int sem_id,int seqnum,int op)
43 {
44     struct sembuf _sm;
45     _sm.sem_num=seqnum;
46     _sm.sem_op=op;
47     _sm.sem_flg=0;
48     if(semop(sem_id,&_sm,1)<0)
49     {
50         perror("semop");
51         return -1;
52     }
53     return 0;
54 }
55 int sem_p_element(int sem_id,int seqnum)
56 {
57     return sem_op(sem_id,seqnum,-1);
58 }
59 int sem_v_element(int sem_id,int seqnum)
60 {
61     return sem_op(sem_id,seqnum,1);
62 }
63 int destory_sem_element(int sem_id)
64 {
65     if(semctl(sem_id,IPC_RMID,0,NULL)<0)
66     {
67         perror("semctl\n");
68         return -1;
69     }
70     return 0;
71 }
//test.c
1 #include"comm.h"
2 int main()
3 {
4     int sem_id=create_sem(1);
5     if(sem_id<0)
6     {
7         printf("error\n");
8         return -1;
9     }
10     init_sem(sem_id,1,1);
11     pid_t pid=fork();
12     if(pid<0)
13     {
14         perror("pid");
15         return -1;
16     }
17     else if(pid==0)
18     {
19         int sem_pid=get_sem(1);
20         while(1)
21         {
22             sem_p_element(sem_pid,0);
23             printf("A");
24             sleep(1);
25             fflush(stdout);
26             printf("A");
27             sleep(8);
28             fflush(stdout);
29             sem_v_element(sem_pid,0);
30         }
31     }
32     else
33     {
34         while(1)
35         {
36             sem_p_element(sem_id,0);
37             sleep(3);
38             printf("B");
39             sleep(2);
40             fflush(stdout);
41             printf("B");
42             sleep(5);
43             fflush(stdout);
44             sem_v_element(sem_id,0);
45         }
46         waitpid(pid,NULL,0);
47         destory_sem_element(sem_id);
48
49     }
50     return 0;
51 }
//Makefile
1 .PHONY:all
2 all:test
3 test:test.c comm.c
4     gcc -o $@ $^
5 .PHONY:clean
6 clean:
7     rm -f test
未使用信号量之前:


使用后:


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  信号量