我有一个包含许多工作线程的C应用程序。至关重要的是这些不会阻塞工作线程需要写入磁盘上的文件,我让它们写入内存中的循环缓冲区,然后有一个专用线程将该缓冲区写入磁盘。
工作线程不再阻塞。专用线程可以在写入磁盘时安全地阻塞,而不会影响工作线程(写入磁盘时它不会保持锁定)。我的内存缓冲区调整得足够大,以至于编写器线程可以跟上。
这一切都很棒。我的问题是,我如何为stdout实现类似的东西?
我可以将macro printf()写入内存缓冲区,但是我无法控制可能写入stdout的所有代码(其中一些代码在第三方库中)。
思考? NickB
答案 0 :(得分:33)
我喜欢使用freopen
的想法。您也可以使用dup和dup2将stdout
重定向到管道,然后使用read
从管道中获取数据。
像这样:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#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;
}
答案 1 :(得分:8)
如果您正在使用GNU libc,则可以使用memory streams。
答案 2 :(得分:4)
您可以使用stdout
将freopen()
“重定向”到文件中。
man freopen
说:
freopen()函数打开文件 其名称是指向的字符串 通过路径并关联流 用它指向溪流。该 原始流(如果存在)是 关闭。使用mode参数 就像在fopen()函数中一样。 freopen()的主要用途 功能是更改文件 与标准文本相关联 stream(stderr,stdin或stdout)。
这个文件可能是一个管道 - 工作线程将写入该管道,编写器线程将监听。
答案 3 :(得分:2)
为什么不将整个应用程序包装在另一个应用程序中?基本上,你想要的是一个聪明的cat
,它将stdin复制到stdout,必要时进行缓冲。然后使用标准的stdin / stdout重定向。这可以在不修改当前应用程序的情况下完成。
~MSalters/# YourCurrentApp | bufcat
答案 4 :(得分:0)
您可以使用setvbuf()
或setbuf()
更改缓冲的工作方式。这里有一个描述:http://publications.gbdirect.co.uk/c_book/chapter9/input_and_output.html。
[编辑]
stdout
确实是FILE*
。如果现有代码与FILE*
一起使用,我看不出有什么阻止它使用stdout
。
答案 5 :(得分:0)
一个解决方案(对于你正在做的事情)将是通过writev使用聚会写作。
每个线程可以例如sprintf到一个iovec缓冲区,然后将iovec指针传递给writer线程,让它只需用stdout调用writev。
以下是使用Advanced Unix Programming
中的writev的示例在Windows下,您可以使用WSAsend来实现类似的功能。
答案 6 :(得分:0)
使用4096 bigbuf的方法只会起作用。我已经尝试过这段代码了,虽然它确实成功地将stdout捕获到缓冲区中,但它在现实世界中无法使用。您无法知道捕获的输出有多长,因此无法知道何时终止字符串'\ 0'。如果您尝试使用缓冲区,如果您已成功捕获96个字符的stdout输出,则会获得4000个字符的垃圾吐出。
在我的应用程序中,我在C程序中使用perl解释器。我不知道在C程序中抛出什么文件会产生多少输出,因此上面的代码永远不会允许我在任何地方干净地打印输出。