声明:侵删
1.信号量概述
信号量也叫信号灯,用于进程/线程同步或互斥的机制
信号灯的类型 : Posix无名信号量 主要用于主要用于线程间的同步和互斥
Posix有名信号量 主要用于进程间同步和互斥
System V 信号量
信号量与其他进程间通信机制不大相同,它主要提供对进程共享资源访问控制机制,相当于内存中的标志,进程可以根据它判定是否能访问某些共享资源,同时,进程也可以修改该标志。除了同于访问控制外,可以用于进程同步。信号量本质上是一个非负的整数计数器。
System V IPC 信号灯特点
SystemV信号灯是一个或多个计数信号灯的集合
可以同时操作集合中的多个信号灯
申请多个资源时避免死锁
System V 信号量使用步骤
①打开/创建信号量 semget
②信号灯初始化 semctl 信号灯只能初始化一次,一般是首个进程对信号量初始化,其余进程只需检测信号灯是否存在即可 ,标志位写IPC_CREAT|0666|IPC_EXCL 通过检查Errno来判断是否是首个进程
③P/V操作 semop
一次 P 操作使信号量sem 减 1, 而一次 V 操作使 sem 加 1。 进程( 线程) 根据信号量的值来判断是否对公共资源具有访问权限。当 sem 的值大于等于 0 时,该进程(或线程)具有公共资源的访问权限;相反,当 sem 的值小于 0 时,该进程(线程)就将阻塞直到 sem 的值大于等于 0 为止
④删除信号量 semctl
2.System V信号量相关函数接口
创建/打开信号量集 获取KEY值 semget函数
信号量的控制 semctl函数
信号量操作函数 semop
3. 例程
sem_com.h
#ifndef _SEM_COM_H
#define _SEM_COM_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo * _buf;
};
int sem_init(int sem_id,int init_value);
int sem_delete(int sem_id);
int sem_p(int sem_id);
int sem_v(int sem_id);
#endif
sem_com.c
#include "sem_com.h"
/* 信号量初始化函数
* 参数 sem_id 由KEY值得到的消耗量集ID
* init_value 信号量初始化值
* 返回值 错误返回-1 成功返回0
*/
int sem_init(int sem_id,int init_value)
{
union semun sem_union;
sem_union.val = init_value;
if (semctl(sem_id,0,SETVAL,sem_union) ==-1 )
{
return -1;
}
else
return 0;
}
/* 信号量集删除函数
* 参数 sem_id 由KEY值得到的信号量集ID
* 返回值 成功 0 失败-1
*/
int sem_delete(int sem_id)
{
if(semctl(sem_id,0,IPC_RMID,NULL) < 0)
{
perror("semctl_delete");
return(-1);
}
else
return 0;
}
/************************************
* p操作函数
* 参数 sem_id 由KEY值得到的信号量集ID
* ***********************************/
int sem_p(int sem_id)
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1; /*-1代表P操作*/
buf.sem_flg = SEM_UNDO; /*进程终止时,系统自动释放残余信号量*/
if(semop(sem_id,&buf,1) < 0 )
{
perror("semop1");
return -1;
}
return 0;
}
/*************************
* V操作函数
* 参数 sem_id 由KEY值得到的信号量集ID
************************/
int sem_v(int sem_id)
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1; /*-1代表P操作*/
buf.sem_flg = SEM_UNDO; /*进程终止时,系统自动释放残余信号量*/
if(semop(sem_id,&buf,1) < 0 )
{
perror("semop2");
return -1;
}
return 0;
}
fork.c
#include "sem_com.h"
#define IPC_PATH "/"
#define IPC_PROJ 1
int main()
{
pid_t pid;
key_t key;
int sem_id;
if ((key = ftok(IPC_PATH,IPC_PROJ)) < 0 )
{
perror("ftok");
exit(-1);
}
if(( sem_id = semget(key,1,IPC_CREAT|0666)) < 0 )
{
perror("semget");
exit(-1);
}
/*初始化第信号量*/
if(sem_init(sem_id,0) < 0 )
{
perror("sem_init");
exit(-1);
}
if ((pid = fork()) < 0) /*少打括号,天天给自己挖坑,注意优先级!!!注意优先级!!注意优先级!!!*/
{
perror("fork");
exit(-1);
}
else if(pid == 0) /*子进程*/
{
printf("Child process will wait for some seconds...\n");
sleep(3);
printf("Child process weakup\n");
sem_v(sem_id); /**资源初始化时为0,V操作(归还资源)sem +1 */
}
else /*父进程*/
{
sem_p(sem_id); /**申请资源堵塞等待,知道信号量的值>0,即子进程执行V操作解除堵塞*/
printf("I'm father, i wakeup\n");
sem_v(sem_id);
sem_delete(sem_id);
}
exit(0);
}
结果