多くのワーカースレッドを持つCアプリケーションがあります。これらがブロックされないことが重要であるため、ワーカースレッドがディスク上のファイルに書き込む必要がある場合は、メモリ内の循環バッファーに書き込み、そのバッファーをディスクに書き込むための専用スレッドを用意します。
ワーカースレッドはこれ以上ブロックしません。専用スレッドは、ワーカースレッドに影響を与えることなく、ディスクへの書き込み中に安全にブロックできます(ディスクへの書き込み中にロックを保持しません)。私のメモリバッファは、ライタースレッドが追いつくことができるように十分に大きくなるように調整されています。
これはすべてうまく機能します。私の質問は、stdoutに似たようなものを実装するにはどうすればよいですか?
マクロprintf()を使用してメモリバッファに書き込むことはできますが、stdoutに書き込む可能性のあるすべてのコードを制御することはできません(一部はサードパーティライブラリにあります)。
考え? NickB
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;
}
GNU libcを使用している場合は、 メモリストリーム を使用できます。
freopen()
を使用して、stdout
をファイルに「リダイレクト」できます。
man freopen
言う:
Freopen()関数は、名前がパスが指す文字列であるファイルを開き、ストリームが指すストリームをそのファイルに関連付けます。元のストリーム(存在する場合)は閉じられます。 mode引数は、fopen()関数と同じように使用されます。 freopen()関数の主な用途は、標準テキストストリーム(stderr、stdin、またはstdout)に関連付けられているファイルを変更することです。
このファイルはパイプである可能性があります。ワーカースレッドはそのパイプに書き込み、ライタースレッドはリッスンします。
アプリケーション全体を別のアプリケーションでラップしてみませんか?基本的に、必要なのは、stdinをstdoutにコピーし、必要に応じてバッファリングするスマートなcat
です。次に、標準のstdin/stdoutリダイレクトを使用します。これは、現在のアプリケーションをまったく変更せずに実行できます。
~MSalters/# YourCurrentApp | bufcat
4096 bigbufを使用する方法は、一種の作業のみを行います。私はこのコードを試しましたが、stdoutをバッファに正常にキャプチャできますが、実際のケースでは使用できません。キャプチャされた出力の長さを知る方法がないため、文字列 '\ 0'をいつ終了するかを知る方法はありません。バッファを使用しようとすると、96文字のstdout出力を正常にキャプチャした場合、4000文字のガベージが吐き出されます。
私のアプリケーションでは、CプログラムでPerlインタープリターを使用しています。 Cプログラムでスローされたドキュメントからどれだけの出力が吐き出されるのかわかりません。したがって、上記のコードでは、その出力をどこにでもきれいに印刷することはできません。
バッファリングがsetvbuf()
またはsetbuf()
でどのように機能するかを変更できます。ここに説明があります: http://publications.gbdirect.co.uk/c_book/chapter9/input_and_output.html 。
[編集]
stdout
は実際にはFILE*
です。既存のコードがFILE*
sで機能する場合、それがstdout
で機能するのを妨げる原因がわかりません。
1つの解決策(両方のことに対して)は、 writev を介して収集書き込みを使用することです。
たとえば、各スレッドはsprintfをiovecバッファーに入れてから、iovecポインターをライタースレッドに渡し、stdoutを使用してwritevを呼び出すだけで済みます。
これは Advanced Unix Programming からwritevを使用する例です。
Windowsでは、同様の機能にWSAsendを使用します。