信号量的本质是一种数据操控锁,它本身不具有数据交换的功能,而是通过来控制其他的通信资源来实现进程间通信的,信号主要负责数据的同步与互斥功能。
进程请求一个使用信号量来表示的资源时,首先要读取信号量的值来判断资源是否能被使用,若信号量的值大于0,资源可用,等于0,无资源可用,同时进程会进入睡眠状态,直到有资源可用。
当进程不再使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操作均为原子操作,这是由于信号量主要的作用是维护资源的互斥或多进程的同步访问。而在信号量的创建及初始化上,不能保证操作均为原子性。
信号量是为了解决多个进程同时访问一块资源所产生的问题的方法,他办证一个时间只有一个进程访问这块资源,按序访问。
信号量的工作原理:
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行
P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。
代码实现成对打印AABB
comm.h
#ifndef _COMM_H_
#define _COMM_H_
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#define PATHNAME "."
#define PROJ_ID 0x6666
#endif
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) */
};
int creatSemSet(int num);
int initSemSet(int semid,int num,int val);
int getSemSet(int num);
int destorySemSet(int semid);
int P(int semid,int num);
int V(int semid,int num);
static int comPV(int semid,int num,int op);
int commSemSet(int num,int flags);
comm.c
#include "comm.h"
int commSemSet(int num,int flags)
{
int _key=ftok(PATHNAME,PROJ_ID);
if(_key<0)
{
perror("ftok");
return -1;
}
int semid=semget(_key,num,flags);
if(semid<0)
{
perror("semget");
return -2;
}
return semid;
}
int creatSemSet(int num)
{
return commSemSet(num,IPC_CREAT|IPC_EXCL|0666);
}
int initSemSet(int semid,int num,int val)
{
union semun _un;
_un.val=val;
if(semctl(semid,num,SETVAL,_un)<0)
{
perror("semctl");
return -1;
}
return 0;
}
int getSemSet(int num)
{
return commSemSet(num,IPC_CREAT);
}
int destorySemSet(int semid)
{
if(semctl(semid,0,IPC_RMID)<0)
{
perror("semctl");
return -1;
}
return 0;
}
static int comPV(int semid,int num,int op)
{
struct sembuf _sf;
_sf.sem_num=num;
_sf.sem_op=op;
_sf.sem_flg=0;
if(semop(semid,&_sf,1)<0)
{
perror("semop");
return -1;
}
return 0;
}
int P(int semid,int num)
{
return comPV(semid,num,-1);
}
int V(int semid,int num)
{
return comPV(semid,num,1);
}
sem.c
#include "comm.h"
int main()
{
int semid=creatSemSet(1);
initSemSet(semid,0,1);
if(fork()==0)
{
int _semid=getSemSet(0);
while(1)
{
P(_semid,0);
printf("A");
fflush(stdout);
sleep(1);
printf("A");
fflush(stdout);
sleep(2);
V(_semid,0);
}
}
else
{
sleep(1);
while(1)
{
P(semid,0);
printf("B");
fflush(stdout);
sleep(2);
printf("B");
fflush(stdout);
sleep(1);
V(semid,0);
}
wait(NULL);
}
return 0;
}
没有P/V操作将不能实现成对打印,不能实现进程之间的同步