Verständnisfrage zu Boost Thread als TimerChecker
-
Guten Abend,
ich habe da mal eine Verständnisfrage: Es geht um einen Timer innerhalb einer Klasse, den ich per Thread periodisch überwachen will. Dazu leg ich den Überwachungs-Thread alle paar Sekunden schlafen.
#include <boost/timer.hpp> #include <boost/bind.hpp> #include <boost/thread.hpp> #include <iostream> class Timer { public: Timer() : timeCheckThread(boost::bind(&Timer::checkTime, this)) {} ~Timer() {std::cerr << "bye "; timeCheckThread.join(); std::cerr << "now";} private: void checkTime() { double elapsed; boost::xtime time; boost::timer timer; while ((elapsed=timer.elapsed()) < 10) { //boost::xtime_get(&time, boost::TIME_UTC); //time.sec += 3; //boost::thread::sleep(time); } std::cerr << "TimeOut" << std::endl; } boost::thread timeCheckThread; }; int main() { Timer t; }Das Interessante ist, dass es mit dem auskommentierten Code (also "ständig" überwachen) zum erwarteten Output kommt. Leg ich den Thread dagegen schlafen, liefert mir elapsed() dagegen immer 0.0 und der Thread kann nicht terminieren.
Liegt es vielleicht daran an dem join() im Destruktor, dass da vorher schon was gelöscht wird? Meine Überlegung mit dieser Implementation war eigentlich, dass das Objekt tatsächlich erst verschwindet, wenn der Timer fertig ist.
Boost-Version ist noch die alte, 1.33... Ausprobiert mit gcc 4.2.1.
-
Lass Dir mal ausgeben wieviele ms Du tasächlich schläfst.
-
boost::xtime_get(&time, boost::TIME_UTC);Das holt dir die aktuelle Zeit in Sekunden seit dem 1.1.1970, was glaub ich ca. 1,2 Milliarden Sekunden sind. Solange wartet dein Sleep dann :p
Übrigens, die aktuelle Boost Version ist bereits 1.35.0 und 1.36.0 geht bald oder ist schon in der Beta. Wäre vielleicht schon mal Zeit die neue Version zu holen. Da funktioniert das Sleep dann auch über Boost.DateTime. Dann musst du wirklich eine TimeDuration übergeben, dürfte weniger Fehleranfällig sein

Im übrigen weiss ich nicht, ob das wirklich so guter Stil ist, in einem Destruktor auf einen Thread zu warten.
Grüssli
-
Im übrigen weiss ich nicht, ob das wirklich so guter Stil ist, in einem Destruktor auf einen Thread zu warten.
Wenn der Thread garantiert "bald mal" terminiert, und Deadlocks ausgeschlossen werden können, dann sehe ich da kein Problem.
Viele Sachen die Leute häufig in einem Dtor aufrufen können recht lange blockieren, ist für mich kein grundlegender Unterschied ob es jetzt um ein join() auf einen Thread geht oder um IO oder sonstwas.
-
@Dravere und tenmpläd: Das Schlafen ist wirklich nicht das Problem. Wenn die Kommentare wieder rauskommen, schläft der Thread wirklich und wird nach der angegebenen Zeit aktiviert, d.h. alle 3 Sekunden in diesem Fall kommt ein Output.
Nur das elapsed() immer 0.0 liefert, der Thread dies ausspuckt und nicht beendet.
Ob das mit dem join() im Dtor guter Stil ist, hmm, kenn mich noch nicht allzugut in der MT-Programmierung aus

Hab mich auch schon gefragt, ob es an der Boost-Version liegt (Implementation hab ich bloss mal überflogen und die Docs konnten mir nicht weiterhelfen). Derzeit wird leider noch an allen Rechnern mit dieser Version gearbeitet.
Vielleicht begreif ich aber auch irgendwas Grundlegendes nicht?
-
Hab mal grad den Quelltext mit Boost 1.35 compiliert und ausgeführt. Auch mit der Verwendung von boost::this_thread::sleep, schreibt der Thread periodisch elapsed = 0.0, ohne dagegen verändert sich der Wert wie erwartet.
Wie kann das sleep einen Einfluss auf die Uhrzeit haben??? boost:
:elapsed() fragt doch bloss std::clock() ab, warum verändert sich dieser Wert nur nicht, wenn der CheckerThread mal kurz schläft? Und sonst schon, wenn er "ständig" drauf zugreift???#include <boost/timer.hpp> #include <boost/bind.hpp> #include <boost/thread.hpp> #include <iostream> class Timer { public: Timer() : timeCheckThread(boost::bind(&Timer::checkTime, this)) {} ~Timer() {std::cerr << "bye "; timeCheckThread.join(); std::cerr << "now";} private: void checkTime() { double elapsed; boost::timer timer; while ((elapsed=timer.elapsed()) < 10) { //boost::this_thread::sleep(boost::posix_time:: milliseconds(2000)); std::cerr << elapsed() << std::endl; } std::cerr << "TimeOut" << std::endl; } boost::thread timeCheckThread; }; int main() { Timer t; }
-
tu mal reindebuggen
-
Also so wie es aussieht, scheint das sleep einen Einfluss auf std::clock() zu haben.
Nehm ich das sleep rein, liefert std::clock() immer Null. Sehr merkwürdig???
-
Also bei mir gibt er mit VS2003/05 und boost 1.35 mit dem sleep
0 ~2 ~4 ~6 ~8 TimeOut bye nowaus
-
Sehr interessant.
Nachdem ich mal noch im Web gesucht, kam ich auf folgenden Link
http://www.gerd-riesselmann.net/development/std-clock-threading-and-linux
Mit dem Workaround funktioniert es wie erwartet (wobei xtime_get auch std::clock verwendet, hmm):
#include <boost/timer.hpp> #include <boost/bind.hpp> #include <boost/thread.hpp> #include <boost/lexical_cast.hpp> #include <iostream> #include <iomanip> class XTimer { public: XTimer() { xtime_get(&_start_time, boost::TIME_UTC); } XTimer(const XTimer& other) : _start_time(other._start_time) { } ~XTimer() { } double elapsed() const { boost::xtime now; xtime_get(&now, boost::TIME_UTC); return boost::lexical_cast<double>(now.sec - _start_time.sec); } private: boost::xtime _start_time; }; class Timer { public: Timer() : timeCheckThread(boost::bind(&Timer::checkTime, this)) {} ~Timer() {std::cerr << "bye "; timeCheckThread.join(); std::cerr << "now";} private: void checkTime() { double elapsed; XTimer timer; while ((elapsed=timer.elapsed()) < 10) { boost::this_thread::sleep(boost::posix_time:: milliseconds(2000)); std::cerr << elapsed() << std::endl; } std::cerr << "TimeOut" << std::endl; } boost::thread timeCheckThread; }; int main() { Timer t; }Hier wird also nicht der boost::timer verwendet, sondern nur auf xtime zurückgegriffen. Trotzdem find ich das strange...
-
Ich korrigiere mich: Ob xtime_get std::clock() ist nicht gegeben, da die Implementation verborgen ist...
-
Ich denke, ich hab die Lösung:
Unter Linux gibt std::clock() die CPU-Zeit für den aktuellen Thread seit Start zurück. Da die while-Schleife nix weiter tut, ausser den Thread sofort wieder schlafen zu legen (und der die Kontrolle wieder abgibt) wird "keine" Zeit verbraucht.
elapsed() gibt also richtig 0 (.0000x) was zurück.