2011-05-19 206 views
2

我正在写一个程序,读取从标准输入回路,使用功能与fgets,如下所示:使用与fgets非阻塞函数C++

while(fgets(buffer2, BUFFERSIZE , stdin) != NULL){ 
    //Some code 
} 

我想我的代码是不可阻挡,那就是:当用户没有输入时,我不希望程序保持'fgets'行。
我该怎么做?

+4

我会这样做使用单独的线程。 – 2011-05-19 08:17:55

回答

1

你基本上有两种选择:

  1. 运行在一个单独的线程循环。
  2. 检查您的操作系统是否支持一些用于非阻塞IO的API。
+2

或3. select()/ poll()等...? :_) – 2011-05-19 08:25:36

+0

@Tony - 实际上,它实际上取决于@Dror需要什么以及整个代码是什么,因为如果它是单个线程,它可能会阻止其他地方,并且不再检查用户输入。 – 2011-05-19 08:27:35

+0

@Kiril:当然......但在提出的问题中没有排除3。干杯。 – 2011-05-19 08:30:59

0

这听起来有点像矫枉过正,但这是我想到的那个。

使用2个不同的线程 - 一个使用这个循环和等待阻塞(我不认为这可以做到非阻塞)。当有东西被读取时,将其推入管道。

与此同时,另一个线程会做任何它需要做的事情,并不时检查管道中的数据(显然,你希望这是异步的,或者至少我是这样做的。意味着不同的线程)

但是,然后,你需要很好地同步这两个线程。您应该检查您的操作系统关于多线程和IO操作。

2

如果你有一个正确的POSIX环境,您可以使用select()poll()调用 fgets() ... read()前检查对stdin的描述符输入。

(谢谢!)低于一月的评论解释了为什么你不能用这种方法使用fgets() ...草率,有缓冲的FILE对象一个额外层和数据已经可以等待虽然select()觉得没有什么更多关于文件描述符......防止您的程序及时响应,并且如果其他系统在发送更多的数据之前正在等待已发送数据的响应,则可能挂起stdin

+1

还不够,你必须把句柄设置为非阻塞模式(因为在再次调用select/poll之前你总是需要读出它,并且这会阻止没有),你需要确保你总是读完它,因为fgets读取的不仅仅是返回值,所以你可能仍然有数据缓存,但select会等待,因为底层描述符没有更多的信息。 – 2011-05-19 08:32:19

+0

@Jan:是的,绝对.. 。傻的我。这意味着 - 没有阻塞的标准输入 - 你必须使用'read()'而不是'fgets()'并且自己处理线条的组合(根据我的经验,这可能会稍微繁琐或者效率稍低)... – 2011-05-19 09:03:26

3

fgets()是一个阻塞函数,它的意思是等待数据可用。

如果要执行异步I/O,您可以使用select()poll(),或epoll()。然后在存在可用数据时从文件描述符执行读取。

这些函数使用FILE *手柄的文件描述符,通过检索:

int fd = fileno(f); 

如果使用的是Unix或Linux,那么一个解决方案,可以标记文件所用的文件描述符是无阻塞。例如:

#include <fcntl.h> 
FILE *handle = popen("tail -f /als/als_test.txt", "r"); 
int fd = fileno(handle); 
flags = fcntl(fd, F_GETFL, 0); 
flags |= O_NONBLOCK; 
fcntl(fd, F_SETFL, flags); 

fgets现在应该非blockng,将返回一个空并设置错误代码为您服务。

+0

请注意非集体性国王I/O - 从我读过的内容来看,它可以与pipes和ttys一起使用,但不是常规文件,因此'./prog Thanatos 2011-05-19 08:38:12

0

在Linux上,您可以通过按ctrl-d来指定输入的结尾,当然,您也可以使用单独的线程来执行此操作。