Pracuję z jakimś wielowątkowym kodem do projektu gry, i mam trochę dość sortowania przez standardowe wymioty utworzone przez dwa wątki używające cout do debugowania wiadomości w tym samym czasie. Zrobiłem trochę badań i przez godzinę lub dwie wpatrywałem się w ścianę, zanim wymyśliłem "coś". Poniższy kod używa SFML do przechowywania i wątkowania. Muteksy SFML są właśnie zapakowane w krytyczne sekcje w oknach.Technika cout safe. Czy czegoś brakuje?
Header:
#include <SFML\System.hpp>
#include <iostream>
class OutputStreamHack
{
public:
OutputStreamHack();
~OutputStreamHack();
ostream& outputHijack(ostream &os);
private:
sf::Clock myRunTime;
sf::Mutex myMutex;
};
static OutputStream OUTHACK;
ostream& operator<<(ostream& os, const OutputStreamHack& inputValue);
realizacji:
#include <SFML\System.hpp>
#include <iostream>
#include "OutputStreamHack.h"
using namespace std;
OutputStreamHack::OutputStreamHack()
{
myMutex.Unlock();
myRunTime.Reset();
}
OutputStreamHack::~OutputStreamHack()
{
myMutex.Unlock();
myRunTime.Reset();
}
ostream& OutputStreamHack::outputHijack(ostream &os)
{
sf::Lock lock(myMutex);
os<<"<"<<myRunTime.GetElapsedTime()<<","<<GetCurrentThreadId()<<"> "<<flush;
return os;
}
ostream& operator<<(ostream& os, const OutputStreamHack& inputValue)
{
OUTHACK.outputHijack(os);
return os;
}
Zastosowanie:
cout<<OUTHACK<<val1<<val2<<val3....<<endl;
Ok, sposób działania jest przez przeciążony operatora wkładania, która nakłada bezpieczeństwa wątku blokując iterator w statycznym obiekcie, a następnie przepłukanie bufora. Jeśli poprawnie rozumiem ten proces (jestem w większości programistą samoukiem), cout przetwarza elementy łańcucha wstawiania od końca do początku, przekazując zmienną ostream w dół łańcucha dla każdego elementu, który ma być dodany do strumienia. Po dotarciu do elementu OUTHACK zostaje wywołany przeciążony operator, muteks jest zablokowany, a strumień jest przepłukiwany.
Dodałem informacje o debugowaniu identyfikatora czasu/wątku do danych wyjściowych w celu weryfikacji. Jak dotąd moje testy pokazują, że ta metoda działa. Mam kilka wątków walących cout z wieloma argumentami, a wszystko wychodzi w odpowiedniej kolejności.
Z tego, co przeczytałem podczas badania tego problemu, brak bezpieczeństwa wątków w cout wydaje się być dość powszechnym problemem, z którym borykają się ludzie, wchodząc w programowanie gwintowe. Próbuję się dowiedzieć, czy technika, której używam, jest prostym rozwiązaniem problemu, czy też myślę, że jestem sprytny, ale brakuje mi czegoś ważnego.
Z mojego doświadczenia wynika, że słowo "sprytny" użyte do opisania programowania jest po prostu hasłem opóźnionego bólu. Czy coś tu jest, czy po prostu gonisz kiepskie hacki w kółko?
Dzięki!
Fakt, że działa, to czysta przyjemność. Tylko wynik identyfikatora czasu i wątku jest chroniony przez muteks. Jest całkiem możliwe, aby inny wątek wkradł się pomiędzy 'OUTHACK' i' val1'. –
Najpierw rozważ pisanie do 'ostringstream', a następnie zrzut zawartości w jednej operacji do' cout'. 'cout' będzie generalnie bezpieczny dla wątków, po prostu blokowanie jest oczywiście dla każdego połączenia, a każda operacja' << 'jest odrębnym połączeniem .... W ten sposób nie ma dodatkowego blokowania w kodzie aplikacji - co może tylko zmniejszyć równoległość. –
Powiązane: [Czy synchronizacja/wątek jest bezpieczny?] (Http://stackoverflow.com/questions/6374264/is-cout-synchronized-thread-safe/6374525#6374525) – legends2k