如何在内存中缓冲stdout并从专用线程写入

我有一个包含许多工作线程的C应用程序。 至关重要的是这些不会阻塞工作线程需要写入磁盘上的文件,我让它们写入内存中的循环缓冲区,然后有一个专用线程将该缓冲区写入磁盘。

工作线程不再阻塞。 专用线程可以在写入磁盘时安全地阻塞,而不会影响工作线程(写入磁盘时它不会保持锁定)。 我的内存缓冲区调整得足够大,以至于编写器线程可以跟上。

一切都很好。 我的问题是,我如何为stdout实现类似的东西?

我可以将macro printf()写入内存缓冲区,但是我无法控制可能写入stdout的所有代码(其中一些代码在第三方库中)。

思考? NickB

我喜欢使用freopen的想法。 您也可以使用dup和dup2将stdout重定向到管道,然后使用read从管道中获取数据。

像这样的东西:

 #include  #include  #include  #define MAX_LEN 40 int main( int argc, char *argv[] ) { char buffer[MAX_LEN+1] = {0}; int out_pipe[2]; int saved_stdout; saved_stdout = dup(STDOUT_FILENO); /* save stdout for display later */ if( pipe(out_pipe) != 0 ) { /* make a pipe */ exit(1); } dup2(out_pipe[1], STDOUT_FILENO); /* redirect stdout to the pipe */ close(out_pipe[1]); /* anything sent to printf should now go down the pipe */ printf("ceci n'est pas une pipe"); fflush(stdout); read(out_pipe[0], buffer, MAX_LEN); /* read from pipe into buffer */ dup2(saved_stdout, STDOUT_FILENO); /* reconnect stdout for testing */ printf("read: %s\n", buffer); return 0; } 

如果您正在使用GNU libc,则可以使用内存流 。

您可以使用freopen()stdout “重定向”到文件中。

man freopen说:

freopen()函数打开文件,该文件的名称是path指向的字符串,并将stream指向的流与它相关联。 原始流(如果存在)已关闭。 mode参数与fopen()函数一样使用。 freopen()函数的主要用途是更改与标准文本流(stderr,stdin或stdout)关联的文件。

这个文件可能是一个管道 – 工作线程将写入该管道,编写器线程将侦听。

为什么不将整个应用程序包装在另一个中? 基本上,你想要的是一个聪明的cat ,它将stdin复制到stdout,必要时进行缓冲。 然后使用标准的stdin / stdout重定向。 这可以在不修改当前应用程序的情况下完成。

 ~MSalters/# YourCurrentApp | bufcat 

您可以使用setvbuf()setbuf()更改缓冲的工作方式。 这里有一个描述: http : //publications.gbdirect.co.uk/c_book/chapter9/input_and_output.html 。

[编辑]

stdout确实是一个FILE* 。 如果现有代码与FILE*一起使用,我看不出阻止它使用stdout

一个解决方案(对于你正在做的事情)将是通过writev使用聚集写入。

每个线程可以例如sprintf到一个iovec缓冲区然后将iovec指针传递给writer线程并让它简单地用stdout调用writev。

以下是使用Advanced Unix Programming中的 writev的示例

在Windows下,您将使用WSAsend来实现类似function。

使用4096 bigbuf的方法只会起作用。 我已经尝试过这段代码,虽然它成功地将stdout捕获到缓冲区中,但它在现实世界中无法使用。 您无法知道捕获的输出有多长,因此无法知道何时终止字符串’\ 0’。 如果您尝试使用缓冲区,如果您已成功捕获96个字符的stdout输出,则会获得4000个字符的垃圾吐出。

在我的应用程序中,我在C程序中使用perl解释器。 我不知道在C程序中抛出什么文件会产生多少输出,因此上面的代码永远不会允许我在任何地方干净地打印输出。