Ich sehe ein Problem, bei dem ein Aufruf von boost's thread->join in einem Destruktor zu einem Deadlock führt. Ich verstehe nicht, warum, und ich bin nicht allzu scharf darauf, Code, der einfach funktioniert (und ich verstehe nicht, warum es tut) in dem Projekt zu halten.
Klassendeklaration (ich habe der Kürze halber die run()-Methode von try/catch entfernt: laut der Boost-Thread-Dokumentation sollte das Ergebnis mit oder ohne sie dasselbe sein):
class B
{
public:
void operator()(){run();}
void run();
void shutdown();
~B();
B();
boost::thread *thr;
bool shutdown_requested;
};
void B::shutdown()
{
shutdown_requested = true;
if (thr != NULL)
{
thr->interrupt();
thr->join(); // deadlock occurs here!
delete thr;
thr = NULL;
}
}
B::~B()
{
shutdown();
}
B::B()
{
thr = new boost::thread(boost::ref(*this));
}
void B::run()
{
while (!shutdown_requested)
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 30;
boost::this_thread::sleep(xt);
}
}
Schnipsel, die nicht funktionieren:
int main()
{
B *b = new B;
Sleep(5000);
printf("deleting \n");fflush(stdout);
// b->shutdown();
delete b;
printf("done\n");fflush(stdout);
return 0;
}
Ein Ausschnitt, der funktioniert:
int main()
{
B *b = new B;
Sleep(5000);
printf("deleting \n");fflush(stdout);
b->shutdown();
delete b;
printf("done\n");fflush(stdout);
return 0;
}
Ich denke, der Grund für dieses Verhalten hat etwas mit diesem Ausschnitt aus der boost-Dokumentation zu tun:
muss der Benutzer von Boost.Thread sicherstellen dass das Objekt, auf das verwiesen wird, den den neu erstellten Ausführungsfaden überdauert.
Aber ich verstehe nicht wirklich, warum die Sackgasse - Beitritt der Thread würde nicht den Destruktor auf B und das Objekt selbst ist nicht gelöscht, wenn die run()-Methode zu beenden soll.