Linux18 进程间通信(三)信号量

信号量:进程同步控制。信号量用来同步进程,像红绿灯控制东西、南北车辆一样。引入信号量会使程序的性能降低,但不同步程序的安全性得不到保障。

进程同步:进程协同工作

进程异步:进程独立运行,互不干扰,但两个进程之间是有关系的,没有关系的进程叫做并发执行,需要内核机制来通知(信号就是一种很好的通知方式。)

临界资源:同一时刻只能被一个进程访问使用的资源,临界资源可以有多份。

临界区:访问临界资源的代码区域。

原子操作:不能被终止的,不能被暂停的操作是原子操作。是一种最小的操作。要么做,要么做完,不可出现中间状态。

i++不是原子操作。

PV操作:是特殊的变量,值的改变是原子操作。P操作:减一,获取资源,如获取不到(信号量为0),就要等待,所以可能阻塞。V操作:加一,释放资源,不会阻塞。

信号量:类似于计数器,>0临界资源可用,申请资源进程执行P操作,则进程会被阻塞。

信号量的内核对象维护的是信号量集  信号量的数组

Linux18 进程间通信(三)信号量

 

1、创建或者获取信号量

int semget((key_t)key,int nsems,int flag);

nsems:创建时,制定信号量集中信号量的个数

 2、控制信号量,初始化或者移除信号量的值

int semctl(int semid,int semnum,int cmd,union semun);
union semun
{
  int val;
  struct semid_ds* buf;
  short* array;
}

 

3、PV操作(改信号量值)

int semop(int semid, struct sembuf buff[],int size);
struct sembuf
{
short  sem_num;
short sem_op;
short sem_flg;
}

封装pv
 

sem.h
# include <sys/sem.h>
union semun
{
         int val;
};
void Sem_init();
void Sem_p();
void Sem_v();
void Sem_destory();

sem.c
# include "sem.h"
static int semid;
void Sem_init()
{
     semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
     if(semid == -1)
      {
          semid = semget((key_t)1234,1,0600);
          if(semid==-1)
            {
                perror("semget error");
                return;
            }
      }
      else
      {
        union semun a;
        a.val=1;
        if(semctl(semid,0,SETVAL,a)==-1)
         {
            perror("semctl error");
         }
      }
      return ;
}

void Sem_p()
{
 struct sembuf buf;
 buf.sem_num = 0;
 buf.sem_op = -1;
 buf.sem_flg = SEM_UNDO;

  if(semop(semid,&buf,1)==-1)
  {
     perror("semop p error");
  }

}

void Sem_v()
{
 struct sembuf buf;
 buf.sem_num = 0;
 buf.sem_op = 1;
 buf.sem_flg = SEM_UNDO;

 if(semop(semid,&buf,1)==-1)
 {
    perror("semop v error");
 }

}

void Sem_destory()
{

   if(semctl(semid,0,IPC_RMID)==-1)
   {
       perror("semcrl error");
   }
}