AT&T的贝尔实验室,对Unix早期的进程间通讯进行了改进和扩充,造成了"system V IPC",其通讯进程主要局限在单个计算机内。IPC对象指的是共享内存(share memory)、消息队列(message queue)和信号灯集(semaphore)。数组
信号灯(semaphore),也叫信号量。缓存
本质;一种数据操做锁(自己是一个计数器,是对临界资源的保护),它自己不具备数据交换的功能,而是经过控制其余的通讯资源(文件,外部设备)来实现进程间通讯,它自己只是一种外部资源的标识。信号量在此过程当中负责数据操做的互斥、同步等功能。ide
当请求一个使用信号量来表示的资源时,进程须要先读取信号量的值来判断资源是否可用。大于0,资源能够请求,等于0,无资源可用,进程会进入睡眠状态直至资源可用。当一个进程再也不使用一个信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减操做为原子操做,这是因为信号量主要的做用是维护资源的互斥或多进程的同步访问。而信号量的建立以及初始化上,不能保证操做为原子操做。函数
使用信号量的缘由:为了防止出现因多个程序同时访问一个共享资源而引起的一系列问题,它能够经过生成并使用令牌来受权,在任意时刻只能有一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码须要独占式地执行。而信号量就能够提供这样的一种访问机制,让一个临界区同一时间只有一个线程在访问它,也就是说信号量是用来协调进程对共享资源的访问的。测试
缺点:建立和初始化分离。spa
信号灯是不一样进程间或一个给定进程内部不一样线程间同步的机制。System V的信号灯是一个或者多个信号灯的一个集合。其中的每个都是单独的计数信号灯。System V 信号灯由内核维护。主要函数semget,semop,semctl。操作系统
一、semget函数:建立一个信号量集对象(获得一个信号量集标识符)线程
函数原型:int semget(key_t key,int nsems,int semflg)3d
key:由ftok()函数的获得对象
nsems:建立信号量集中信号的个数
semflg:
IPC_CREAT:若内核中不存在键值与key相等的信号量集,则建立,不然,返回此信号量集的标识符
IPC_EXCL:单独使用无心义
IPC_CREAT | IPC_EXCL :建立一个新的信号量集并返回信号量集的标识符,不然,返回-1.
返回值:成功返回信号量集的标识符。失败返回-1.
二、semctl函数:在指定的信号集或信号集内的某个信号上执行操做控制
函数原型:int semctl(int semid,int semnum,int cmd,union semun arg)
semid: 信号量集标识符
semnum:信号量集数组上的下标,表示某一个信号量
arg:
union semun {
short val; /*SETVAL用的值*/
struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构*/
unsigned short* array; /*SETALL、GETALL用的数组值*/
struct seminfo *buf; /*为控制IPC_INFO提供的缓存*/
} arg;
三、semop函数:对信号量进行P,V操做(本文的重点)
P操做负责把当前进程由运行状态转换为阻塞状态,直到另一个进程唤醒它。操做为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;
V操做负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操做为:释放一个被占用的资源(把信号量加1),若是发现有被阻塞的进程,则选择一个唤醒之。
semop函数原型以下:
int semop(int semid, struct sembuf *sops, unsigned nsops);
semop操做中:sembuf结构的sem_flg成员能够为0、IPC_NOWAIT、SEM_UNDO 。为SEM_UNDO时,它将使操做系统跟踪当前进程对这个信号量的修改状况,若是这个进程在没有释放该信号量的状况下终止,操做系统将自动释放该进程持有的。
sembuf结构的sem_flg成员为SEM_UNDO时,它将使操做系统跟踪当前进程对这个信号量的修改状况,若是这个进程在没有释放该信号量的状况下终止,操做系统将自动释放该进程持有的信号量,从而使另一个进程能够继续工做,防止其余进程由于得不到信号量而发生【死锁现象】。为此通常建议使用SEM_UNDO。
测试代码:
sem.h
sem.c
semtest.c
运行结果: