目录
Linux系统上存在两套信号量标准:SYSTEM V信号量和POSIX信号量。
1.SYSTEM V信号量
头文件:
#inlclude <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
(1) 创建或打开:semget
int semget(key_t key, int nsems, int semflg);
成功返回信号量ID,失败返回-1
key:信号量集键值,常用ICP_PRIVATE由系统分配
nsems:信号量个数
semflg:常用IPC_CREAT代表没有新建信号量集则创建
m=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
新建一个只有一个信号量的私有信号量集m
(2) 申请或释放:semop
int semop(int semid, struct sembuf *sops, unsigned nsops);
semid:信号量集ID
sops:操作定义的结构体
nsops:操作次数
semop(m,&sem_b,1);
struct sembuf sem_b;
sem_b.semnum=0;//要操作的信号量在信号量集中的索引,从0开始
sem_b.sem_op=-1;//负P正V
sem_b.sem_flg=SEM_UNDO;//进程意外结束时,进行UNDO
利用sem_b对m信号量集中索引为0的第一个信号做wait(P)操作
sem_b长度为1,意思是只做一个操作
进程意外结束时,将已做的wait进行UNDO
(3) 设置信号量:semctl
int semctl(int semid, int semnum, int cmd, union semun arg);
semid:信号量集ID
semnum:要操作的信号量在信号量集中的索引,从0开始
cmd:要执行的命令
SETVAL:设置一个信号量值
GETVAL:返回一个信号量值
arg:与cmd搭配使用
semctl(m,0,SETVAL,1);
设置信号量集m中第一个信号量的初值为1
2.POSIX信号量
(1) 初始化:sem_init
int sem_init(sem_t *sem, int pshared, unsigned int value);
sem:指向信号量的指针
pshared:0代表当前进程的所有线程共享,1代表进程间共享
value:信号量初值
(2) 申请和释放:sem_wait
int sem_wait(sem_t *sem);
减1为0则阻塞
int sem_post(sem_t *sem);
数值加1
(3) 销毁:sem_destroy
int sem_destroy(sem_t *sem);
sem:指向信号量的指针
(4) 获得信号量值:sem_getvalue:
int sem_getvalue(sem_t *sem, int *sval);
sem:指向信号量的指针
sval:获得的值保存在sval中
获得信号量的值,若阻塞则获得阻塞的进程/线程数,值保存到sval中
3.进程同步与互斥
(1)进程互斥
设有一个房间资源,一次只能一个进程使用,用信号量操作模拟3个进程互斥使用房间,输入q杀死进程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
//5-13:进程互斥
int room = 0;
char ch;
int main(int argc,char argv[]) {
pid_t pid;
pid_t pids[2];
int i=0;
int j=0;
struct sembuf sem_b;
sem_b.sem_num=0;
sem_b.sem_flg=SEM_UNDO;
//创建控制进入房间的信号量
room=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
//互斥信号量room赋初值为1
semctl(room,0,SETVAL,1);
for (i=0;i<=2;i++) {
pid=fork();//父亲循环几次,创建几个子进程。子进程由于while(1)不进入for循环
if (pid==0){
while(1){//子进程循环,父亲不进
printf("%d want to enter room--WAIT\n",getpid());
sem_b.sem_op = -1; //申请资源,操作数为1
semop(room,&sem_b,1); //此两句是信号量操作的申请wait
printf("%d is in room\n",getpid());
sleep(3);
sem_b.sem_op = 1; //释放资源,操作数为1
semop(room,&sem_b,1); //此两句是信号量操作的释放signal
printf("%d is out of room---SIGNAL OK\n",getpid());
}//while
}
else{
pids[i]=pid;//父亲
}
}//for
do{
ch=getchar();
if (ch == 'q')
for (i=0;i<=2;i++)
kill(pids[i],SIGTERM);
}while(ch != 'q');
} //main
父亲for循环3次,生成3个儿子,3个儿子进出房间

(2)进程同步
1个盘子能放1个水果,儿子读书累了就拿水果吃,没有水果就等待;父亲和母亲都不断给儿子放水果,盘子满了就不能放。用信号量操作模拟这3个进程的运行过程。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
//5-14:进程同步
int e; //empty of plate
int f; //fruit
int waitsem(int sem_id) {
//把信号量操作封装到函数中,提高代码可读性
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,1) == -1){
fprintf(stderr, "P failed\n");
return 0; }//if
return 1;
}
int signalsem(int sem_id){
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if(semop(sem_id,&sem_b,1) == -1){
fprintf(stderr, "V failed\n");
return 0; }//if
return 1;
}
int main(int argc,char argv[]){
pid_t pid;
pid_t pids[2];
int i=0;
char ch;
e=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
//创建e信号量用于控制对 盘子空资源 的使用
f=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
//创建f信号量用于控制对 水果

本文介绍了进程和线程间的同步互斥机制,包括SYSTEMV和POSIX信号量的使用,互斥锁与条件变量的应用,并通过多个实例展示如何解决实际问题。
最低0.47元/天 解锁文章
1669

被折叠的 条评论
为什么被折叠?



