Umleitung für stdout



  • Kann ein Prozess seine eigenen Ausgaben an stdout abfangen? Alle gefundenen Beispiele sind darauf ausgelegt, die Ausgaben anderer Prozesse einzufangen. Beim eigenen Prozess gibt es aber Probleme.

    Dieser Code aus ist diversen Tipps und Beispielen aus dem Netz zusammengeschustert:

    Setup:

    static const char *PIPENAME_OUT = "\\\\.\\pipe\\LOOPBACK_STDOUT";
    
    mOutPipe = CreateNamedPipe(PIPENAME_OUT, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 4096, 4096, 500, 0);
    if(mOutPipe != INVALID_HANDLE_VALUE)
        freopen(PIPENAME_OUT, "wb", stdout);
    ... 	
    if(mOutPipe != INVALID_HANDLE_VALUE)
        mPipeThread.run();
    

    Thread:

    while(true)
    {	
        fflush(stdout);
        while(PeekNamedPipe(mOutPipe, 0, 0, 0, &total, 0) && total > 0)
        {
            DWORD rd = 0;
            if(ReadFile(mOutPipe, StdOutBuffer, STDBUFFERSIZE-1, &rd, 0))
            {
                 // ausgabe...
            }
        }
        Sleep(50);
    }
    

    Mit diesem Code hagelt es Deadlocks in WriteFile (das indirekt von printf/cout aufgerufen wird) in unregelmäßigen Abständen. Die Umleitung funktioniert prinzipiell.

    Ich würde gerne wissen, wie eine solche Umleitung korrekt umgesetzt werden muss, dass ein Prozess seine eigene Ausgaben verlässlich darstellen kann.



  • int hCrt;
       FILE *hf;
    
       hCrt = _open_osfhandle(
                 (long) hNamedPipeHandle,
                 _O_TEXT
              );
       hf = _fdopen( hCrt, "w" );
       *stdout = *hf;
       i = setvbuf( stdout, NULL, _IONBF, 0 );
    


  • Und in Deinem Thread darfst Du *keine* CRT Funktionen verwenden! Und schon gar nicht "fflush"!!!



  • Danke, werd ich mal probieren. Warum darf ich in meinem Thread keine CRT-Funktionen aufrufen? Das fflush ist (zumindest bisher) notwendig, sonst wäre die Umleitung witzlos. Ich möchte sofort ausgeben, nicht erst wenn der Puffer voll ist.



  • Das geht deshalb nicht, da die CRT einen Lock auf den stdout hat. Wenn Du nun auch noch fflush aufrufst, versucht dieser zuerst den stdout zu locken... und dann hast Du einen dead-lock...
    Mach das fflush in dem Teil wo Du auch das printf o.ä. machst.

    ADD: Und wenn Du

    setvbuf( stdout, NULL, _IONBF, 0 );
    

    aufrufst, sollte eigentlich das Buffern ausgeschaltet sein...



  • Funktioniert leider nicht, die Pipe bleibt leer.

    mOutPipe = CreateNamedPipe(PIPENAME_OUT, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 4096, 4096, 500, 0);
    if(mOutPipe != INVALID_HANDLE_VALUE)
    {
        int hCrt = _open_osfhandle((intptr_t)mOutPipe, _O_TEXT);
        FILE *hf = _fdopen(hCrt, "w");
        *stdout = *hf;
        setvbuf(stdout, NULL, _IONBF, 0);
    }
    ...
    


  • Ich habs mal geändert in

    mOutPipe = CreateNamedPipe(PIPENAME_OUT, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, 4096, 4096, 500, 0);
    if(mOutPipe != INVALID_HANDLE_VALUE)
    {
        FILE *out = freopen(PIPENAME_OUT, "w", stdout);
        assert(out);
        setvbuf(out, NULL, _IONBF, 0);
    }
    

    fflush brauche ich so nicht mehr. Das scheint zu funktionieren. Irgendwelche Einwände?



  • Wunderbar... freopen ist sogar besser 😉


Anmelden zum Antworten