linux c 使用fifo管道进行多线程间通信

144 篇文章 6 订阅

创建有名管道,如果管道存在则直接使用

//创建有名管道,如果管道存在则直接使用
    int n = mkfifo("./myfifo",0664);
    if( n < 0 && errno!=EEXIST)
    {
        perror("mkfifo");
        return -1;
    }

负责管道写数据线程

void *thread_fun_write(void *p)
{
    char *buf = "12345";
    int fd;
    fd = open("./myfifo",O_WRONLY);
    if(fd == -1)
    {
        printf("write fifo open fail....\n");
        exit(-1);
        return;
    }
    while(1)
    {
        write( fd, buf, strlen(buf)+1 );
        puts("write ok");
        sleep(5);
    }
    close(fd);
}

        负责读取管道内容的线程,如果管道内没有数据,阻塞等待读取数据。

void *thread_fun_read(void *p)
{

    int fd;

    fd = open("./myfifo", O_RDONLY );
    if(fd == -1)
    {
        printf("read fifo open fail...\n");            
        exit(-1);
        return;
    }
    char buf[100] = {0};
    int num;//保存读数据大小
    while(1)
    {
        num = read( fd, buf, 100 );
        puts("read ok:");
        puts(buf);
    }
    close(fd);
}


        完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

void *thread_fun_write(void *p)
{
    char *buf = "12345";
    int fd;
    fd = open("./myfifo",O_WRONLY);
    if(fd == -1)
    {
        printf("write fifo open fail....\n");
        exit(-1);
        return;
    }
    while(1)
    {
        write( fd, buf, strlen(buf)+1 );
        puts("write ok");
        sleep(5);
    }
    close(fd);

}
void *thread_fun_read(void *p)
{

    int fd;

    fd = open("./myfifo", O_RDONLY );
    if(fd == -1)
    {
        printf("read fifo open fail...\n");            
        exit(-1);
        return;
    }
    char buf[100] = {0};
    int num;//保存读取数据的大小
    while(1)
    {
        num = read( fd, buf, 100 );
        puts("read ok:");
        puts(buf);
    }
    close(fd);
}
int main()
{
    //创建有名管道,如果管道存在则直接使用
    int n = mkfifo("./myfifo",0664);
    if( n < 0 && errno!=EEXIST)
    {
        perror("mkfifo");
        return -1;
    }
    //创建线程
    pthread_t writeId,readId;
    pthread_create( &writeId, NULL, thread_fun_write, NULL );
    pthread_create( &readId, NULL, thread_fun_read, NULL);

    pthread_join(writeId,NULL);
    pthread_join(readId,NULL);
    while(1);
    return 0;
}

        若想实现写进程阻塞,读进程非阻塞。只需将读进程中管道打开方式改为

fd=open("./myfifo",O_RDONLY | O_NONBLOCK);

        先运行写进程(被阻塞),再运行读进程,程序一切正常。先运行读进程,程序直接崩掉(Segmentation fault (core dumped))。

        此外,用户还可能想着,我在读取的时候,使用阻塞的方式的话,会一直卡着;使用非阻塞的方式,则会没完没了的调用while(1)占用了CPU还不干活。

        有没有在阻塞的情况下再提供超时的机制呀?比如,我尝试等待5s,如果在这5s内,管道中有数据,则我就读取,如果么有,我就进入下一次循环,继续等待5s。而这等待过程中不占用CPU。

        有!但是完全不占用CPU是不可能的。

        首先,我们不能使用while(1)这种方式,这货不释放CPU,没完没了的去尝试从管道中拿数据;

        其次,我们也不能使用sleep(0.5)或者类似的等待机制(比如衰退式的睡眠时间等),这会造成另外一个问题,睡眠时释放了CPU,但是如果在睡眠过程中管道里有数据了,这种方式只能在睡眠结束后去拿数据,可能黄花菜都凉了;

        最后,操作系统提供了select系统调用,可使用它来完成超时机制的设置,但是这个是与文件绑定的,具体地是和fd绑定的。在select调用过程中,如果指定的fd发生了事件(具体什么事件,去看看select的介绍),则select会返回大于0的数值,此时就可以执行之后的代码;如果在等待过程中没有产生事件,则返回小于0的数值,那就可以进入下一次循环,而不用执行后续操作。通过这种在读管道之前加入超时的方式,变相地实现了带超时机制的读数据。但是在这种情况下,读管道是否为堵塞其实都没有意义了,因为无论是设置成堵塞还是非堵塞,前面的select都会执行,也就是都会堵塞。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值