蛋疼了很久,漏了一个括号,结果在shmat返回错误Identifier removed...废话不多说,最后解释。。
信号量,很多人把他和mutex进行类比,是的,可以简单认为mutex是信号量只在0-1变化的。不过二者还是有些差别的(现在我还没深入到。。),信号量表示资源数,如果信号量大于0,则表示他还有val个资源可以被获取,当val<=0时候表示没有信号量了,这里出现小于0是表示有多少进程在等待。
共享内存使得多个进程能够通过共享的内存区域进行通信。这个最大的好处就是在server/client上实现二者通信。
但是共享内存的过程有个同步问题随之而来,server什么时候去取得共享区域数据,什么时候不能取呢,我首先想到的就是用信号呗,确实,不过这里有个条件,client要知道server的pid,server也要知道client的pid,这个当然也是可以的。
还有一种方法就是采用信号量的方式(可以暂时理解成用锁的形式)来阻塞某一端,直至数据准备就绪再去取得数据。
我这里用个网络上很流行的案例,server-client
---------------------------------------
设计目的:实现client向server传递数据,只有在client发送完毕后,server才取得数据,否则阻塞等待。
设计思路:1、首先运行服务器,创建一个共享内存区域,存放数据;
2、同时创建一个semid,注意,信号量一般是多个(不像mutex就是一个0-1状态,这里semid表示信号量的id)
int semid=semget(ket_t key,int nsems,int flag) key就是IPC的键了,nsems表示这个semid里有多少个信号量,flag表示权限,一般IPC_CREAT|IPC_EXCL|0666(注意下,IPC_EXCL这个表示如果key已经被绑定过则报错,这个在服务器里可以使用,但是客户机上就不要用IPC_EXCL当然IPC_CREAT也不用了),创建好semid。
3、这里细致说下sembuf和union semun
struct sembuf{
unsigned short sem_num;//表示semid的第几个信号量0开始计数
short sem_op;//表示semop()函数后的操作,正:则向val加上sem_op;负:则val+(sem_op);当然也可以为0
short sem_flg;//IPC_NOWAIT SEM_UNDO
}
union semun{
int val;//这个表示信号量的资源数 很关键的数,就是上面说的val
}
4、后面的步骤就是围绕这些进行,看代码把
--------------------server--------------------------------------------
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9
10 #define SEM_KEY 4001
11 #define SHM_KEY 5678
12
15
16
17 int semid,shmid;
18 int *shmptr;
19 struct sembuf sembuf1;
20 union semun {
21 int val;
22 };
23
24 int main(void)
25 {
26 //create a shm
27 if((shmid = shmget(SHM_KEY,sizeof(int),IPC_CREAT|0666))<0){
28 printf("create shm error\n");
29 retur;
30 }
31 if((shmptr = shmat(shmid,NULL,0))==(int*)-1){
32 printf("shmat error:%s\n",strerror(errno));
33 return 1;
34 }
35 semid = semget(SEM_KEY,2,IPC_CREAT|0666);//这里是创建一个semid,并且有两个信号量
36 union semun semun1;//下面这四行就是初始化那两个信号量,一个val=0,另一个val=1
37 semun1.val=0;
38 semctl(semid,0,SETVAL,semun1);
39 semun1.val=1;
40 semctl(semid,1,SETVAL,semun1);
41
42 //
43 while(1){
44 sembuf1.sem_num=0;//sem_num=0指的是下面操作指向第一个信号量,上面设置可知其 //val=0
45 sembuf1.sem_op=-1; //这里定义操作是-1,但是他已经为0 了,所以会阻塞,48行就产生 //了这个阻塞
46 sembuf1.sem_flg=SEM_UNDO;
47
48 semop(semid,&sembuf1,1);//服务器在这里会阻塞,下面看下client
49 printf("the NUM:%d\n",*(shmptr));//输出结果
50
51 sembuf1.sem_num=1;//这里让客户端再次就绪,就这样循环
52 sembuf1.sem_op=1;
53 sembuf1.sem_flg=SEM_UNDO;
54
55 semop(semid,&sembuf1,1);
56 }
57 return 0;
58 }
--------------------------client-------------------------------
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7
8 #define SEM_KEY 4001
9 #define SHM_KEY 5678
10
13
14
15 int semid,shmid;
16 int *shmptr;
17 struct sembuf sembuf1;
18 union semun {
19 int val;
20 };
21
22 int main(void)
23 {
24 //create a shm
25 if((shmid = shmget(SHM_KEY,sizeof(int),0666))<0){
26 printf("create shm error\n");
27 return 1;
28 }
29 if((shmptr =shmat(shmid,NULL,0))==(int*)-1){
30 printf("shmat error\n");
31 return 1;
32 }
33 semid = semget(SEM_KEY,2,0666);
34 union semun semun1;
35
36 //
37 while(1){
38 sembuf1.sem_num=1;//这里指向第2个信号量(sem_num=1)
39 sembuf1.sem_op=-1;//操作是-1,但是第二个信号量初始值为1,所以下面不会阻塞
40 sembuf1.sem_flg=SEM_UNDO;
41
42 semop(semid,&sembuf1,1);//继续
43 scanf("%d",shmptr); //用户客户端输入数据
44
45 sembuf1.sem_num=0;//这里指向第一个信号量
46 sembuf1.sem_op=1;//操作加1
47 sembuf1.sem_flg=SEM_UNDO;
48
49 semop(semid,&sembuf1,1);//执行+1后,我们发现,服务器阻塞正是由于第一个信号量为0,无法减一,而现在客户端先为其加1,那服务器就绪!客户端继续循环,发现第二个信号量已经减为0,则阻塞了,我们回到服务器
50 }
51 return 0;
52 }
--------------------------------------------------------------