通过信号量PV操作实现,同步互斥机制

如果你不了解信号和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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值