Linux下的关于信号量的总结《二》

关于信号量的基础理论知识请看:https://blog.csdn.net/qq_42418668/article/details/95166917
 

使用信号量和管道

实现A进程写内容到管道中,B进程不立刻的读取而是等A进程写完并且退出后B进程才读取。这里的A进程和B进程使用信号量来实现这个效果。

我们对semget semop semctl进行封装如下

sem.h

#ifndef __SEM_H

#define __SEM_H

typedef union semun
{
    int val;
}Semun;

int sem_init(int key,int nsems,int semval[]);//return semid

void sem_p(int semid,int sems[],int size);

void sem_v(int semid,int sems[],int size);

void sem_del(int semid);

#endif

sem.c:

#include "sem.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>


int sem_init(int key,int nsems,int semval[])//return semid
{
    int semid = semget((key_t)key,0,0664);
    if(semid != -1)
    {
        return semid;
    }
    semid = semget((key_t)key,nsems,IPC_CREAT|0664);
    assert(semid!=-1);
    int i=0;
    for(;i<nsems;++i)
    {
        Semun sem;
        sem.val = semval[i];
        semctl(semid,i,SETVAL,sem);
    }
    return semid;
}

void sem_p(int semid,int sems[],int size)
{
    struct sembuf buff[size];
    int i = 0;
    for(;i<size;++i)
    {
        buff[i].sem_num = sems[i];
        buff[i].sem_op = -1;
        buff[i].sem_flg = SEM_UNDO;
    }
    semop(semid,buff,size);
}

void sem_v(int semid,int sems[],int size)
{
    struct sembuf buff[size];
    int i = 0;
    for(;i<size;++i)
    {
        buff[i].sem_num = sems[i];
        buff[i].sem_op = 1;
        buff[i].sem_flg = SEM_UNDO;
    }
    
    semop(semid,buff,size);
}

void sem_del(int semid)
{
    if(-1 == semctl(semid,0,IPC_RMID))
    {
        printf("delete error\n");
        exit(0);
    }
}

进程A的相关代码:

/*================================================================
*   Copyright (C) 2019 . All rights reserved.
*   
*   文件名称:main.c
*   创 建 者:gaojie
*   创建日期:2019年07月08日
*   描    述:
*
================================================================*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#include "sem.h"
#include <fcntl.h>

int main()
{
    int val=0;

    int semid = sem_init(1234,1,&val);
    int fd = open("FIFO",O_WRONLY);
    assert(fd != -1);
    while(1)
    {
        printf("please input:\n");
        char buff[128]={0};
        fgets(buff,128,stdin);
        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        
        write(fd,buff,strlen(buff)-1);
    }
    int sem = 0;
    sem_v(semid,&sem,1);
    close(fd);
}

进程B的相关代码

/*================================================================
*   Copyright (C) 2019 . All rights reserved.
*   
*   文件名称:mainb.c
*   创 建 者:gaojie
*   创建日期:2019年07月08日
*   描    述:
*
================================================================*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

#include <fcntl.h>
#include "sem.h"

int main()
{
    int val = 0;
    int semid = sem_init(1234,1,&val);

    int fd = open("FIFO",O_RDONLY);
    printf("open FIFO success\n");
    assert(-1!=fd);

    int sem = 0;
    sem_p(semid,&sem,1);
    char buff[1024]={0};
    int n =read(fd,buff,1023);

    if(n<=0)
    {
        printf("error\n");
        exit(0);
    }

    printf("data length = %d \n",strlen(buff));
    printf("%s\n",buff);
    close(fd);
}

如果我们注释掉进程A和进程B的关于信号量的相关操作

可以看到我们的进程A输入完一次之后,进程B接受到并且退出,由于管道必须有一段读,一段写才可以正常工作,所以B退出后A也随着B的退出而退出。

但是我们加上信号量"阻塞"进程B的接受数据,此时进程B必须要等待进程A释放临界区资源才可以进入临界区代码。所以最后的结果是进程B一直等待进程A将临界区资源释放,而A释放临界区资源的终止条件就是往管道中写入数据完毕,当A完成向管道中的写入数据操作后,进程A进行了v操作,将由于等待临界区资源而被挂起的进程B重新唤醒,然后B读到管道中的数据然后输出。整个过程完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值