23

多くのワーカー スレッドを持つ C アプリケーションがあります。これらがブロックされないようにすることが不可欠です。そのため、ワーカー スレッドがディスク上のファイルに書き込む必要がある場合は、メモリ内の循環バッファーに書き込むようにし、そのバッファーをディスクに書き込むための専用スレッドを用意します。

ワーカー スレッドはブロックしなくなります。専用スレッドは、ワーカー スレッドに影響を与えることなく、ディスクへの書き込み中に安全にブロックできます (ディスクへの書き込み中にロックを保持しません)。メモリ バッファは、ライター スレッドが維持できる十分な大きさになるように調整されています。

これはすべてうまくいきます。私の質問は、標準出力に似たものをどのように実装するのですか?

printf() をマクロ化してメモリ バッファーに書き込むことはできますが、stdout に書き込む可能性のあるすべてのコードを制御することはできません (一部はサードパーティ ライブラリにあります)。

考え?ニックB

4

7 に答える 7

35

を使用するというアイデアが気に入っていfreopenます。dupdup2stdoutを使用してパイプにリダイレクトし、 を使用してパイプからデータを取得することもできます。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;
}
于 2009-06-05T14:45:38.120 に答える
9

GNU libc を使用している場合は、メモリ ストリーム string ストリームを使用できます。

于 2009-06-05T14:10:05.603 に答える
4

stdoutを使用してファイルに「リダイレクト」できますfreopen()

man freopen言う:

freopen()関数は、名前がパスが指す文字列であるファイルを開き、ストリームが指すストリームをそのファイルに関連付けます。元のストリーム(存在する場合)は閉じられます。mode引数は、fopen()関数と同じように使用されます。freopen()関数の主な用途は、標準テキストストリーム(stderr、stdin、またはstdout)に関連付けられているファイルを変更することです。

このファイルはパイプである可能性があります。ワーカースレッドはそのパイプに書き込み、ライタースレッドはリッスンします。

于 2009-06-05T13:57:06.080 に答える
2

アプリケーション全体を別のアプリケーションでラップしてみませんか? 基本的に、cat必要に応じて標準入力を標準出力にコピーし、バッファリングするスマートが必要です。次に、標準の stdin/stdout リダイレクトを使用します。これは、現在のアプリケーションをまったく変更せずに実行できます。

~MSalters/# YourCurrentApp | bufcat
于 2009-06-05T14:08:14.123 に答える
0

setvbuf()またはでバッファリングの動作を変更できますsetbuf()。ここに説明があります:http://publications.gbdirect.co.uk/c_book/chapter9/input_and_output.html

[編集]

stdout本当にですFILE*。既存のコードがFILE*sで機能する場合、それがで機能するのを妨げるものがわかりませんstdout

于 2009-06-05T13:58:02.460 に答える
0

1 つの解決策 (両方のことに対して) は、writevを介して収集書き込みを使用することです。

各スレッドは、たとえば sprintf を iovec バッファーに入れ、iovec ポインターをライター スレッドに渡し、単純に stdout を使用して writev を呼び出すことができます。

Advanced Unix Programmingの writev の使用例を次に示します。

Windows では、同様の機能に WSAsend を使用します。

于 2009-06-05T14:11:32.650 に答える
0

4096 bigbuf を使用する方法は、ある程度機能するだけです。このコードを試してみましたが、標準出力をバッファに正常にキャプチャできますが、実際には使用できません。キャプチャされた出力の長さを知る方法がないため、文字列 '\0' をいつ終了するかを知る方法はありません。バッファを使用しようとすると、96 文字の stdout 出力を正常にキャプチャした場合、4000 文字のガベージが吐き出されます。

私のアプリケーションでは、C プログラムで perl インタープリターを使用しています。Cプログラムでスローされたドキュメントからどれだけの出力が吐き出されるかはわかりません。したがって、上記のコードでは、その出力をどこにでもきれいに印刷することはできません。

于 2010-04-26T12:28:51.283 に答える