信号量
信号量用于进程同步互斥。信号量可以直接理解成计数器,信号量会有初始值>0,每当进程申请使用信号量,通过P操作来对信号量进行-1操作。当计数器(信号量)减到0时说明没有资源了,其他进程要访问就必须在临界区外等待,该进程执行完临界区操作之后,就会执行V操作来对信号量进行+1操作。
临界区:只能被一个进程同时使用(不可多个进程共享),要用到互斥。
(1)创建信号量
semget(key,nsems,semflg):成功返回信号量的id,失败时返回-1,并设置errno值。
key:和信号量所关联的key值,由ftok()函数的返回值得到;
nsems:创建的信号量的个数,传0则代表通过key值获取信号量id;
semflg:IPC_CREAT 和 IPC_EXCL,传0代表不做创建的动作;
(2)信号量的初始化
semctl(semid,semnum,cmd,…):初始化信号量,成功返回0,失败返回-1,并设置errno值。
semid:信号量id,由semget()函数的返回值得到。
semnum:要初始化第几个信号量,信号量编号从0开始;
cmd:SETVAL;
参数4:union semnum类型的共用体,填共用体中的成员val,在填之前要对其赋值。联合体中的val 是信号量的初始值。
(3)信号量操作:
semop(semid,struct sembuf *sops,nsops):成功返回0,失败返回-1
semid:信号量id,由semget()函数的返回值得到;
struct sembuf *sops
{
sem_num;//你想操作的信号量的下标
sem_op;//值给1或-1,代表V和P操作
sem_flg;//信号量选项,IPC_NOWAIT(非阻塞)等等,没有选项填0即可
}
nsops:要同时操作几个信号量
(4)删除信号量
semctl(semid,0,IPC_RMID);
例、用多进程实现打印出AABBAABB…的字符串。
sem.h头文件:封装信号量的相关操作
#ifndef SEM_H__
#define SEM_H__
int sem_create(int semnum);
int sem_get();
int sem_init(int semid,int index);
int sem_p(int semid,int index,int nums);
int sem_v(int semid,int index,int nums);
int sem_destroy(int semid,int index);
#endif
sem.c程序:对信号量的操作写自定义函数
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sem.h>
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) */
};
static int sem_create_comon(int semnum,int ctl)
{
key_t key;
int semid;
key = ftok("sem.c",'a');
if(key < 0)
{
perror("ftok()");
return -1;
}
semid = semget(key,semnum,ctl);
if(semid < 0)
{
perror("semget()");
return -2;
}
return semid;
}
int sem_create(int semnum)
{
return sem_create_comon(semnum,IPC_CREAT|0666);
}
int sem_get()
{
return sem_create_comon(0,0);
}
int sem_init(int semid,int index)
{
union semun semn;
semn.val = 1;
if(semctl(semid,index,SETVAL,semn) < 0)
{
perror("semctl()");
return -1;
}
return 0;
}
static int sem_vp(int semid,int index,int nums,int vp)
{
struct sembuf sops;
sops.sem_num = index;
sops.sem_op = vp;
sops.sem_flg = 0;
if(semop(semid,&sops,nums) < 0)
{
perror("semop()");
return -1;
}
return 0;
}
int sem_p(int semid,int index,int nums)
{
return sem_vp(semid,index,nums,-1);
}
int sem_v(int semid,int index,int nums)
{
return sem_vp(semid,index,nums,1);
}
int sem_destroy(int semid,int index)
{
return semctl(semid,index,IPC_RMID);
}
print.c程序:打印出AABBAABB…的序列
#include <stdio.h>
#include <stdlib.h>
#include <sem.h>
int main(void)
{
pid_t pid;
int semid;
semid = sem_create(1);
sem_init(semid,0);
if( (pid = fork()) < 0)
{
perror("fork()");
exit(-1);
}
if(pid == 0)
{
semid = sem_get();
while(1)
{
sem_p(semid,0,1);
printf("B");
fflush(NULL);
sleep(1);
printf("B");
fflush(NULL);
sem_v(semid,0,1);
}
exit(0);
}
while(1)
{
sem_p(semid,0,1);
printf("A");
fflush(NULL);
sleep(1);
printf("A");
fflush(NULL);
sem_v(semid,0,1);
}
wait(NULL);
sem_destory(semid,0);
exit(0);
}
Makefile文件:
CFLAGS+=-I./
main:sem.c print.c
$(CC) -o $@ $^ $(CFLAGS)
对于信号量这个知识点,博主没有理解透彻,恳请高手指点!