1. 信号量简介
命名管道以及消息队列用于一个进程给另一个进程发送数据
与之相比,信号量并不是为了进程间通信,而是提供了一个多个进程间共享的计数器
计数器为正数,进程可以获取信号量(一个或者多个),这时候共享计数器减去进程拿走的数字;也可以放回信号量(一个或者多个),这时候共享计数器加上放回的数字
最重要的是:进程获取信号量时,会得到操作系统支持
[操作系统提示信号量不够减并且进程返回] 或者 [操作系统把调用进程挂起,直到信号量足够减去进程要求的数字时,调用进程返回]
2 信号量结构
- IPC对象 信号量集
信号量不能单独表示,它存在于信号量集结构中:一个信号量集可能包含多个信号量
一个信号量集合对应一个IPC对象,使用一个sem_ds结构表示
3 信号量接口
3.1 设计图示
设计三个进程:
进程A负责创建信号量集/IPC 对象 并且该信号量拥有两个信号
信号量初始值设计为10
进程A对信号量1和2进行获取释放操作(一次9个),进程B01,B02分别对信号量01 02进行获取释放操作(一次2个),因为双方进行异步操作,势必发生冲突
3.2 示例代码(未完成…按照下面的代码,进程A和进程B始终无法产生冲突,待调试)
进程A
#include <iostream>
extern "C"
{
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
/*
SVr4, POSIX.1-2001.
int semget(key_t key, int nsems, int semflg);
int semctl(int semid, int semnum, int cmd, ...);
int semop(int semid, struct sembuf *sops, size_t nsops);
*/
}
using namespace std;
int main()
{
key_t sem_key = 444;
unsigned short array[3]={10,10,10};
int res = 0;
/**/
int sem_id = semget(sem_key,3,IPC_CREAT|IPC_EXCL|0600);
if(-1 == sem_id)
{
cout << "semget failed,exiting" << endl;
goto ErrEnd;
}
/**/
res = semctl(sem_id,2,SETALL,array);
if(-1 == res)
{
cout << "semctl init failed,exiting" << endl;
goto ErrEnd;
}
/*
*/
struct sembuf oparr[4];
oparr[0].sem_num = 0;
oparr[0].sem_op = 9;
oparr[0].sem_flg = IPC_NOWAIT|SEM_UNDO;
oparr[1].sem_num = 1;
oparr[1].sem_op = 9;
oparr[1].sem_flg = IPC_NOWAIT|SEM_UNDO;
oparr[2].sem_num = 0;
oparr[2].sem_op = -9;
oparr[2].sem_flg = IPC_NOWAIT|SEM_UNDO;
oparr[3].sem_num = 1;
oparr[3].sem_op = -9;
oparr[3].sem_flg = IPC_NOWAIT|SEM_UNDO;
while(1)
{
res = semop(sem_id,oparr,1);
if(res == -1)
{
if(errno == EAGAIN)
{
cout << "0 Egain try" << endl;
}
else
{
cout << "0 Other case" << endl;
}
}
else
{
sleep(3);
res = semop(sem_id,&oparr[2],1);
if(res == -1)
{
cout << "0 release failed" << endl;
}
else
{
cout << "0 release ok" << endl;
}
sleep(1);
}
res = semop(sem_id,&oparr[1],1);
if(res == -1)
{
if(errno == EAGAIN)
{
cout << "1 Egain try" << endl;
}
else
{
cout << "1 Other case" << endl;
}
}
else
{
res = semop(sem_id,&oparr[3],1);
if(res == -1)
{
cout << "1 release failed" << endl;
}
else
{
cout << "1 release ok" << endl;
}
sleep(1);
}
}
return 0;
ErrEnd:
semctl(sem_id,0,IPC_RMID);
return -1;
}
进程B
#include <iostream>
extern "C"
{
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
/*
SVr4, POSIX.1-2001.
int semget(key_t key, int nsems, int semflg);
*/
}
using namespace std;
int main(int argc, char* argv[])
{
key_t sem_key = 444;
int sem_id = semget(sem_key,0,0600);
if(-1 == sem_id)
{
cout << "semget open failed,exiting" << endl;
return -1;
}
int sem_num = 0;
if(*argv[1] == '1')
{
sem_num = 1;
}
struct sembuf oparr[2];
oparr[0].sem_num = sem_num;
oparr[0].sem_op = 2;
oparr[0].sem_flg = IPC_NOWAIT|SEM_UNDO;
oparr[1].sem_num = sem_num;
oparr[1].sem_op = -2;
oparr[1].sem_flg = IPC_NOWAIT|SEM_UNDO;
while(1)
{
int res = semop(sem_id,oparr,1);
if(res == -1)
{
if(errno == EAGAIN)
{
cout << "Egain " << sem_num << endl;
}
else
{
cout << "other case" << endl;
}
}
else
{
sleep(3);
res = semop(sem_id,&oparr[1],1);
if(res == -1)
{
cout << "release failed" << endl;
}
else
{
cout << "release ok" << endl;
}
sleep(1);
}
}
return 0;
}