2010-11-25 9 views
2

Je crée une application de console win32 en C++. J'utilise une API (pas la mienne, et je ne peux pas modifier ses sources). Il est écrit de sorte qu'il écrit certaines de ses informations sur l'écran de la console ne demande pas ... chaque fois que je l'appelle (48 fois par seconde) Donc je veux le mettre dans un fil et limiter ses capacités de sortie, mais je dois obtenir notifié lorsque ce thread va essayer de sortir un message qui est important pour moi. J'ai le texte du message dans la chaîne standard. Comment faire une telle chose en C++ en utilisant boost?Boost: comment créer un thread pour pouvoir contrôler toutes ses sorties standards, les erreurs standards?

Répondre

1

Cette fonctionnalité n'existe pas dans Boost. Vous pouvez toutefois utiliser _dup2 pour remplacer le descripteur sortie standard:

#include <cstddef> 
#include <cstdio> 
#include <cstdlib> 
#include <io.h> 
#include <iostream> 
#include <windows.h> 

int main() 
{ 
    HANDLE h = CreateFile(TEXT("test.txt"), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 
    if (0 == SetStdHandle(STD_OUTPUT_HANDLE, h)) { 
     std::fprintf(stderr, "`SetStdHandle` failed with error %d\n", (int)GetLastError()); 
     return EXIT_FAILURE; 
    } 

    int h_desc = _open_osfhandle((long)h, 0); 
    _dup2(h_desc, STDOUT_FILENO); 

    std::printf("test\r\n"); // This actually writes to `h`. 
    std::fflush(stdout); 

    std::cout << "another test" << std::endl; // Also writes to `h` 

    CloseHandle(h); 
    return EXIT_SUCCESS; 
} 

Essentiellement ce que cette astuce n'est vous permet de rediriger toutes les écritures de stdout, std::cout et GetStdHandle(STD_OUTPUT_HANDLE) à une poignée inscriptible de votre choix (h) . Bien sûr, vous pouvez utiliser CreatePipe pour créer le handle inscriptible (h) et lire à partir de l'extrémité lisible dans un autre thread.

EDIT: Si vous cherchez une solution multi-plateforme, notez que cette astuce est encore plus facile sur les systèmes compatibles POSIX, car dup2 est une fonction standard dans unistd.h et « poignées inscriptible » sont des descripteurs déjà.

1

Je ne peux pas trouver un moyen de réaliser dans Boost ce que vous voulez, car le problème est décrit.

Toutefois, ce comportement API est très perplexe. Cracher des rames de sortie sur la console est un peu antisocial. Utilisez-vous une version Debug de la bibliothèque d'API? Êtes-vous sûr qu'il n'y a aucun moyen de configurer l'API de telle sorte qu'elle produise ces données sur un flux différent, de sorte que vous puissiez les filtrer sans capturer toute la sortie standard? Existe-t-il un moyen de réduire la quantité de sortie, afin que vous ne voyiez que les événements importants qui vous intéressent? Si vous avez vraiment besoin de capturer une sortie standard et d'agir sur certaines chaînes (événements) d'intérêt, alors Win32 fournit des moyens de le faire, mais je vais vraiment vérifier si cette sortie peut être modifiée pour répondre à vos besoins. besoins avant de recourir à cela.

2

Voilà une idée folle:

Si la lib utilise Cout/cerr, vous pouvez remplacer le streambuf de ces variables globales avec une mise en œuvre de votre propre. Sur flush/data, il vérifie une variable thread-local pour voir si les données proviennent du thread qui appelle la bibliothèque, puis l'achemine ailleurs (c'est-à-dire dans un std :: string/std :: ostringstream) au lieu de les streambufs cout/cerr réguliers. (Ce que vous devriez garder autour.)

S'il utilise c stdout/stderr, je pense que ce serait plus difficile à faire correctement, mais cela pourrait être encore faisable. Vous auriez besoin de créer des tuyaux et d'acheminer les choses d'avant en arrière. Plus d'une question C/Unixy alors, que je ne connais pas beaucoup sur ... encore. :)

J'espère que ça aide.

Questions connexes