关于多线程 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;
}
反思
与我联系
我的微信公众号,扫二维码即可关注: