信号量的本质是一种数据操做锁,它自己不具备数据交换的功能,而是经过控制其余的
通讯资源(文件,外部设备)来实现进程间通讯, 它自己只是一种外部资源的标识。信号量在此过程当中负责数据操做的互斥、同步等功能。当请求一个使用信号量来表示的资源时,进程须要先读取信号量的值来判断资源是否能够。大于0,资源能够请求,等于0,无资源可用,进程会进入睡眠状态直到资源可用。当进程再也不使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操做均为原子操做,这是因为信号量主要的做用是维护资源的互斥或多进程的同步访问。但在信号量的建立及初始化上,不能保证操做均为原子性。
ide
1、为何要使用信号量?
spa
为了防止出现因多个程序同时访问一个共享资源时引起的一系列问题,咱们须要一种方法,它能够经过生成并使用令牌来受权,在任什么时候刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码须要独占式地执行。而信号量就能够提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它, 也就是说信号量是用来调协进程对共享资源的访问的。其中共享内存的使用就要用到信号量。
线程
2、 信号量的工做原理orm
因为信号量只能进行两种操做等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):若是sv的值大于零,就给它减1;若是它的值为零,就挂起该进程的执行;
V(sv):若是有其余进程因等待sv被挂起,就让它恢复运行,若是没有进程因等待sv而挂起,就给它加1.举个例子,就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操做,它将获得信号量,并能够进入临界区,使sv减1。而第二个进程将被阻塞进入临界区,由于当它试图执行P(sv)时, sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就能够恢复执行。
进程
代码以下:ip
comm.h:内存
#pragma once资源
#include<stdio.h>get
#include<sys/types.h>同步
#include<sys/ipc.h>
#include<sys/sem.h>
#include<errno.h>
#include<unistd.h>
#define _PROJ_NAME_ "/tmp"
#define _PROJ_ID_ 0X666
union semun{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};
int creat_sem_set(int sems);
int get_sem_set();
int init_sem_set(int sem_id,int which,int _val);
int destory_sem_set(int sem_id);
int P(int sem_id,int which);
int V(int sem_id,int which);
comm.c:
#include"comm.h"
static int comm_sem_set(int sems,int flags)
{
key_t _key=ftok(_PROJ_NAME_,_PROJ_ID_);
if(_key<0)
{
perror("ftok");
return -1;
}
int sem_id=semget(_key,sems,flags);
if(sem_id<0)
{
perror("semget");
return -1;
}
return sem_id;
}
int creat_sem_set(int sems)
{
int flags=IPC_CREAT|IPC_EXCL|0644;
return comm_sem_set(sems,flags);
}
int get_sem_set()
{
int flags=IPC_CREAT;
return comm_sem_set(0,flags);
}
int init_sem_set(int sem_id,int which,int _val)
{
union semun _un;
_un.val=_val;
if(semctl(sem_id,which,SETVAL,_un)<0){
perror("semctl");
return -1;
}
return 0;
}
int destory_sem_set(int sem_id)
{
if(semctl(sem_id,0,IPC_RMID)<0)
{
perror("semctl");
return -1;
}
return 0;
}
static int op(int sem_id,int which,int op)
{
struct sembuf _sem;
_sem.sem_num=which;
_sem.sem_op=op;
_sem.sem_flg=0;
if(semop(sem_id ,&_sem, 1)<0){
perror("semop");
return -1;
}
return 0;
}
int P(int sem_id,int which)
{
return op(sem_id,which,-1);
}
int V(int sem_id,int which)
{
return op(sem_id,which,1);
}
test_sem.c:
#include"comm.h"
int main()
{
int sem_id=creat_sem_set(1);
//sleep(10);
init_sem_set(sem_id,0,1);
pid_t id=fork();
if(id==0){
int c_sem_id=get_sem_set();
while(1){
P(c_sem_id,0);
printf("A");
fflush(stdout);
usleep(rand()%12345);
printf("A");
fflush(stdout);
usleep(rand()%123415);
V(c_sem_id,0);
}
}else
{
while(1){
P(sem_id,0);
printf("C");
fflush(stdout);
usleep(rand()%12344);
printf("C");
fflush(stdout);
usleep(rand()%123454);
V(sem_id,0);
}
wait(NULL);
destory_sem_set(sem_id);
}
return 0;
}