进程间通信之System V 信号量

声明:侵删

1.信号量概述

信号量也叫信号灯,用于进程/线程同步或互斥的机制
信号灯的类型 : Posix无名信号量 主要用于主要用于线程间的同步和互斥
Posix有名信号量 主要用于进程间同步和互斥
System V 信号量

信号量与其他进程间通信机制不大相同,它主要提供对进程共享资源访问控制机制,相当于内存中的标志,进程可以根据它判定是否能访问某些共享资源,同时,进程也可以修改该标志。除了同于访问控制外,可以用于进程同步。信号量本质上是一个非负的整数计数器。

System V IPC 信号灯特点
SystemV信号灯是一个或多个计数信号灯的集合

可以同时操作集合中的多个信号灯

申请多个资源时避免死锁

System V 信号量使用步骤
①打开/创建信号量 semget
②信号灯初始化 semctl 信号灯只能初始化一次,一般是首个进程对信号量初始化,其余进程只需检测信号灯是否存在即可 ,标志位写IPC_CREAT|0666|IPC_EXCL 通过检查Errno来判断是否是首个进程
③P/V操作 semop
一次 P 操作使信号量sem 减 1, 而一次 V 操作使 sem 加 1。 进程( 线程) 根据信号量的值来判断是否对公共资源具有访问权限。当 sem 的值大于等于 0 时,该进程(或线程)具有公共资源的访问权限;相反,当 sem 的值小于 0 时,该进程(线程)就将阻塞直到 sem 的值大于等于 0 为止
④删除信号量 semctl

2.System V信号量相关函数接口

创建/打开信号量集 获取KEY值 semget函数

在这里插入图片描述
信号量的控制 semctl函数
在这里插入图片描述在这里插入图片描述

信号量操作函数 semop
在这里插入图片描述

3. 例程

sem_com.h

#ifndef _SEM_COM_H
#define _SEM_COM_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun
{
	int val;
	struct semid_ds *buf;
	unsigned short *array;
	struct seminfo * _buf;
};

int sem_init(int sem_id,int init_value);
int sem_delete(int sem_id);
int sem_p(int sem_id)int sem_v(int sem_id)#endif 

sem_com.c

#include "sem_com.h"

/*  信号量初始化函数
 *  参数        sem_id  由KEY值得到的消耗量集ID
 *             init_value 信号量初始化值
 *  返回值      错误返回-1 成功返回0
 */
int sem_init(int sem_id,int init_value)
{
    union semun sem_union;
    sem_union.val = init_value;
    if (semctl(sem_id,0,SETVAL,sem_union) ==-1 )
    {
       
        return -1;
    }
    else 
        return 0;
}
/* 信号量集删除函数
 * 参数        sem_id 由KEY值得到的信号量集ID
 * 返回值       成功 0  失败-1
 */
int sem_delete(int sem_id)
{
  if(semctl(sem_id,0,IPC_RMID,NULL) < 0)
  {
      perror("semctl_delete");
      return(-1);
  }
  else 
    return 0;

}
/************************************
 * p操作函数
 * 参数         sem_id 由KEY值得到的信号量集ID
 * ***********************************/
int sem_p(int sem_id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = -1; /*-1代表P操作*/
    buf.sem_flg = SEM_UNDO; /*进程终止时,系统自动释放残余信号量*/
    if(semop(sem_id,&buf,1) < 0 )
    {
        perror("semop1");
        return -1;
    }
    return 0;
}

/*************************
 * V操作函数
 * 参数      sem_id 由KEY值得到的信号量集ID
 ************************/
int sem_v(int sem_id)
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1; /*-1代表P操作*/
    buf.sem_flg = SEM_UNDO; /*进程终止时,系统自动释放残余信号量*/
    if(semop(sem_id,&buf,1) < 0 )
    {
        perror("semop2");
        return -1;
    }
    return 0;
}

fork.c

#include "sem_com.h"

#define IPC_PATH "/"
#define IPC_PROJ 1

int main()
{
    pid_t pid;
    key_t key;
    int sem_id;
    if ((key = ftok(IPC_PATH,IPC_PROJ)) < 0 ) 
    {
        perror("ftok");
        exit(-1);
    }
    
    if(( sem_id = semget(key,1,IPC_CREAT|0666)) < 0 )
    {
        perror("semget");
        exit(-1);
    }
    /*初始化第信号量*/
    if(sem_init(sem_id,0) < 0 )
    {
        perror("sem_init");
        exit(-1);
    }

    if ((pid = fork()) < 0) /*少打括号,天天给自己挖坑,注意优先级!!!注意优先级!!注意优先级!!!*/
    {
        perror("fork");
        exit(-1);
    }
    
    else if(pid == 0) /*子进程*/
    {
        printf("Child process will wait for some seconds...\n");
        sleep(3);
        printf("Child process weakup\n");
        sem_v(sem_id); /**资源初始化时为0,V操作(归还资源)sem +1 */
    }
   
    else  /*父进程*/
    {
        sem_p(sem_id); /**申请资源堵塞等待,知道信号量的值>0,即子进程执行V操作解除堵塞*/
        printf("I'm father, i wakeup\n");
        sem_v(sem_id);
        sem_delete(sem_id);
    }
   
    exit(0);
}

结果

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值