linux IO复用之select

15 篇文章 0 订阅

关于多线程 select的阻塞退出问题

前言

我们在编程的时候,经常会遇到阻塞的问题,比如read函数会阻塞,所以我们可以用select来监所有的fd,但是select本身也会阻塞,直到有事件发生,那么当select阻塞的时候,又没有事件发生的时候,我们想退出程序,但这时候select依然是阻塞的,这是我们可以怎么办呢
第一个办法,我们可以设置超时,但是这个方法毕竟每一段时间都会返回一次,如果这个事件不经常发生,就不太适用了。
第二个办法,我们可以再监控一个fd,当我们退出的时候,出发这个文件描述符的事件,这样就可以退出。

相比之下,第二种方法相对好一些,省资源。所以这篇博客简单探讨一下。

代码示例

最近在网上偶然看到这篇博客
https://blog.csdn.net/eydwyz/article/details/76638168
我们可以监控eventfd这个fd,用来作为退出的标志。

简单介绍:因为想让select随时响应事件的发生,所以我们让select在单独的一个线程运行,主程序做我们想做的业务。
因为使用了多线程中,当我们发送sigint信号的时候,其实只有一个线程会受到这个信号,是哪个线程收到,是有系统决定的(参考网上的说法,自己没有验证),所以可以用上面的方法出发select的退出。

完整代码如下所示


//参考博客,https://blog.csdn.net/eydwyz/article/details/76638168

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/select.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>

//eventfd
#include <sys/eventfd.h>
#include <stdint.h>



char is_running = 1;

void signalstop(int signal)
{
    printf("catch signal!\n");
    is_running = 0;  
}

void *thread_loop(void *arg)
{
    printf("into thread_loop!\n");
    char buf_read[256] = {0};
    int efd = *(int *)arg;

    fd_set allset;
    fd_set fdset;
    FD_ZERO(&allset);
    FD_ZERO(&fdset);
    FD_SET(STDIN_FILENO, &allset);
    FD_SET(efd, &allset);

    int max_fd = efd > STDIN_FILENO ? efd : STDIN_FILENO;
    while (1)
    {
        fdset = allset;
        printf("select wait......\n");
        int nready = select(max_fd+1, &fdset, NULL, NULL, NULL);
        if (nready <= 0)
        {
            perror("select error:");
            break;
        }

        if (FD_ISSET(STDIN_FILENO, &fdset))
        {
            memset(buf_read, 0, sizeof(buf_read));
            printf("event STDIN_FILENO\n");
            read(STDIN_FILENO, &buf_read, sizeof(buf_read));
            printf("input is %s\n", buf_read);
        }

        if (FD_ISSET(efd, &fdset))
        {
            printf("event efd\n");
            uint64_t u = 0;
            ssize_t s = read(efd, &u, sizeof(uint64_t));  
            if (s != sizeof(uint64_t))  
                perror("read");  
            printf("read %llu efd\n",(unsigned long long)u);
            break;
        }
    }
    printf("exit from thread_loop!\n");
    return 0;
}

int main(int argc, char *argv[])
{
    signal(SIGINT, signalstop);

    int efd = eventfd(0, 0);
    if (efd == -1)
        perror("efd init\n");

    pthread_t thread;
    int ret_thrd1 = pthread_create(&thread, NULL, thread_loop, &efd);
    if (ret_thrd1 != 0)
    {
        printf("creat thread failed!\n");
        return 0;
    }

    while (is_running)
    {
        sleep(1);
    }

    uint64_t u = 10;
    ssize_t s = write(efd, &u, sizeof(uint64_t));
    if (s != sizeof(uint64_t))
        perror("write");

    pthread_join(thread, NULL);
    close(efd);
    printf("exit from main!\n");

    return 0;
}


反思

与我联系

我的微信公众号,扫二维码即可关注:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chasentech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值