如果你不了解信号和PV操作,可以看我上篇博客,这篇主要是实现同步互斥。
场景:当一个进程和另一个进程在同时使用一个临界资源时,会变得错乱,所以我们需要通过信号量的PV操作,来加同步互斥。
前言:1操作系统是通过数组来管理信号量的数量的。
2,P操作,是对信号量进行减减,V操作是对信号进行加加,(当信号量小于0时,会等待,这就是同步)。
3.当信号量的数为1时,我们可以实现互斥(先给一个进程进行P操作,结束后进行V操作),这样就达到了互斥。
4.消费者模型,让篇博客里有,很全面
具体:fork出两个进程,让它们同时在显示器输出,当他们是成对出现的时候,就很好的实现了同步与互斥。
头文件:
#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;
#define PATHNAME "."
#define PROJ_ID 0x6666
union semun
{
int val; //value for SERVAL
struct semid_ds *but; //Buffer for IPC_STAT,IPC_SET
unsigned short *array; //Array for GETALL,SERALL
struct seminfo *_buf; //Buffer for IPC_INFO
};
int createSemSet(int nums);
int initSem(int semid,int nums,int initVal);
int getSemSet(int nums);
int P(int semid,int who);
int V(int semid ,int who);
int destroySemSet(int semid);
函数实现文件:
#include"comm.h"
using namespace std;
static int commSemSet(int nums,int flags)
{
key_t key = ftok(PATHNAME,PROJ_ID);
if(key < 0)
{
perror("ftok");
exit(-1);
}
int semid = semget(key,nums,flags);
if(semid < 0)
{
perror("semget");
exit(-1);
}
return semid;
}
int createSemSet(int nums)
{
int semmid = commSemSet(nums,IPC_CREAT|IPC_EXCL|06666);
return semmid;
}
int initSem(int semid,int nums,int initVal)
{
union semun _un;
_un.val = initVal;
if(semctl(semid,nums,SETVAL,_un)< 0)
{
perror("semctl");
return -3;
}
return 0;
}
int getSemSet(int nums)
{
return commSemSet(nums,IPC_CREAT);
}
static int commPV(int semid,int who,int op)
{
struct sembuf _sf;
_sf.sem_num = who;
_sf.sem_op = op;
_sf.sem_flg = 0;
if(semop(semid,&_sf,1) < 0)
{
perror("semop");
return -1;
}
return 0;
}
int P(int semid,int who)
{
return commPV(semid,who,-1);
}
int V(int semid ,int who)
{
return commPV(semid,who,1);
}
int destroySemSet(int semid)
{
if(semctl(semid,0,IPC_RMID) < 0)
{
perror("semctl");
exit(-1);
}
return 0;
}
测试文件:
#include"comm.h"
int main()
{
int semid = createSemSet(1);
initSem(semid,0,1);
pid_t id = fork();
if(id == 0)
{
//int _semid = getSemSet(0);
while(1)
{
P(semid,0);
cout << "我是子进程,我正在用显示器";
fflush(stdout);
cout <<endl;
sleep(2);
cout << "我已经用完了";
fflush(stdout);
cout << endl;
V(semid,0);
}
} else
{
while(1)
{
P(semid,0);
cout << "我是父进程,我正在用显示器";
fflush(stdout);
cout << endl;
sleep(3);
cout << "我已经用完了";
fflush(stdout);
cout << endl;
V(semid,0);
}
wait(NULL);
}
destroySemSet(semid);
return 0;
}
另外这是我的Makefile:
test:comm.cpp comm.h test_sem.cpp
g++ -o $@ $^
.PHONY:clean
clean:
rm -f test