Cómo almacenar el stdout en memoria y escribirlo desde un hilo dedicado

Tengo una aplicación C con muchos hilos de trabajo. Es esencial que estos no se bloqueen, por lo tanto, cuando los subprocesos de trabajo necesitan escribir en un archivo en el disco, los escribo en un búfer circular en la memoria y luego tengo un hilo dedicado para escribir ese búfer en el disco.

Los hilos de trabajo no bloquean más. El subproceso dedicado puede bloquearse de forma segura mientras se escribe en el disco sin afectar los subprocesos de trabajo (no mantiene un locking mientras se escribe en el disco). Mi buffer de memoria está ajustado para ser lo suficientemente grande como para que el hilo del escritor pueda mantener el ritmo.

Todo esto funciona genial Mi pregunta es, ¿cómo implemento algo similar para stdout?

Podría imprimir macrof () para escribir en un búfer de memoria, pero no tengo control sobre todo el código que podría escribir en stdout (parte de él está en bibliotecas de terceros).

¿Pensamientos? NickB

Me gusta la idea de usar freopen . También es posible que pueda redirigir la salida estándar a una tubería usando dup y dup2 , y luego usar read para tomar datos de la tubería.

Algo así:

 #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; } 

Si está trabajando con la libc de GNU, puede usar flujos de memoria .

Puede “redirigir” stdout en el archivo usando freopen() .

man freopen dice:

La función freopen () abre el archivo cuyo nombre es la cadena a la que apunta la ruta y asocia la secuencia a la que apunta la transmisión. La secuencia original (si existe) está cerrada. El argumento mode se usa igual que en la función fopen (). El uso principal de la función freopen () es cambiar el archivo asociado con una secuencia de texto estándar (stderr, stdin o stdout).

Este archivo bien podría ser un hilo: los hilos del trabajador escribirán en ese tubo y el hilo del escritor lo escuchará.

¿Por qué no envuelves toda tu aplicación en otra? Básicamente, lo que quieres es un cat inteligente que copie stdin a stdout, buffering según sea necesario. Luego use la redirección estándar stdin / stdout. Esto se puede hacer sin modificar su aplicación actual en absoluto.

 ~MSalters/# YourCurrentApp | bufcat 

Puede cambiar cómo funciona el almacenamiento en búfer con setvbuf() o setbuf() . Aquí hay una descripción: http://publications.gbdirect.co.uk/c_book/chapter9/input_and_output.html .

[Editar]

stdout realmente es un FILE* . Si el código existente funciona con FILE* s, no veo qué impide que funcione con stdout .

Una solución (para las dos cosas que hace) sería usar una recostackción de escritura a través de writev .

Cada hilo podría, por ejemplo, pasar a un buffer iovec y luego pasar los punteros iovec al hilo del escritor y hacer que simplemente llame a writev con stdout.

Aquí hay un ejemplo del uso de writev de la progtwigción avanzada de Unix

En Windows, usaría WSAsend para una funcionalidad similar.

El método que usa el bigbuf 4096 solo funcionará. Probé este código, y si bien logra capturar stdout en el búfer, es inutilizable en un caso del mundo real. No tiene forma de saber cuánto dura la salida capturada, por lo que no hay forma de saber cuándo finalizar la cadena ‘\ 0’. Si intenta utilizar el búfer, obtendrá 4000 caracteres de basura si hubiera capturado con éxito 96 caracteres de salida stdout.

En mi aplicación, estoy usando un intérprete de Perl en el progtwig C. No tengo idea de cuánto saldrá el resultado de cualquier documento que se arroje al progtwig C, y por lo tanto, el código anterior nunca me permitirá imprimir ese resultado en cualquier lugar.