一、信号量:(数据操作锁)控制进程间互斥、同步等,协调多个程序同时访问一个共享资源。
工作原理:信号量只能有两种操作等待和操作,即:P V操作,必须是原子操作。
P(sv):如果 sv 的值大于零就减一;如果它的值为零,就挂起;
V(sv):如果有被挂起的,恢复运行,如果没有就加一。
二、函数原型:
int semget(key_t key, int nsems,int semflg);
int semop(int semid,struct sembuf *sops,size_t nsops);
int semctl(int semid, int semnum, int cmd, ...);
/*
* semid:信号量集的标识符; semnum:第几个信号量;
* cmd:需要执行的命令,根据命令的不同,函数有三个或四个参数(union)
*/
cmd:IPC_RMID,立即删除信号集,唤醒被阻塞的进程;
cmd:SETVAL,设置信号量集中的一个单独的信号量的值。
cmd:GETALL用于读取信号量集中的所有信号量的值。
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};//用户需自己定义声明
struct sembuf
{
unsigned short sem_num;
short sem_op;
short sem_flg;
};
三、代码实现:
//sem.h
#pragma once#include#include #include #include #include #include #include #define _PATH_ "."#define _ID_ 0x666static int op_sem(int sem_id, int op, int which);int creat_sem(int _sem_num);int get_sem();int init_sem(int _sem_id, int _which);int sem_p(int _sem_id, int _which);int sem_v(int _sem_id, int _which);int destroy_sem(int _sem_id);union semun{ int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf;};
//sem.c
#include"sem.h"int creat_sem(int snum){ int flags = IPC_CREAT|IPC_EXCL|0666; key_t key = ftok(_PATH_, _ID_); if(key < 0) { perror("ftok"); return -1; } return semget(key, snum, flags);}int get_sem(){ key_t key = ftok(_PATH_, _ID_); if(key < 0) { perror("ftok"); return -1; } return semget(key, 0, IPC_CREAT);}static int op_sem(int sem_id, int op, int which){ struct sembuf sem; memset(&sem, '\0',sizeof(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 sem_p(int sem_id, int which){ return op_sem(sem_id, -1, which);}int sem_v(int sem_id, int which){ return op_sem(sem_id, 1, which);}int init_sem(int sem_id, int which){ union semun _semun; _semun.val = 1; if(semctl(sem_id, SETVAL, which, _semun) < 0) { perror("semctl"); return -1; } return 0;}int destroy_sem(int sem_id){ if(semctl(sem_id, 0, IPC_RMID, NULL) < 0) { perror("semctl"); return -1; } return 0;}
//test.c
#include"sem.h"int main(){ int sem_id = creat_sem(1); if(sem_id < 0) { printf("creat_sem error"); return -1; } init_sem(sem_id, 0); pid_t id = fork(); if(id < 0) { perror("fork"); return -1; } else if(id == 0) { int sem_id = get_sem(1); while(1) { sem_p(sem_id, 0); printf("A"); sleep(1); fflush(stdout); printf("A"); sleep(2); fflush(stdout); sem_v(sem_id, 0); } } else { while(1) { sem_p(sem_id, 0); printf("B"); fflush(stdout); printf("B"); sleep(1); fflush(stdout); sem_v(sem_id, 0); } waitpid(id, NULL, 0); destroy_sem(sem_id); } return 0;}
四、实现结果:
使用信号量之前
使用信号量之后