boost :: thread: Segfault wenn optimierte Version läuft
-
05-09-2019 - |
Frage
Ich habe Mühe, boost:thread
zu arbeiten. Es läuft gut, wenn ohne Optimierung kompilieren:
g++ -o test-thread test-thread.cpp -lboost_thread-gcc-mt-s -lpthread
./test-thread
Aber eine Version, die mit Optimierungen Abstürze
kompiliertg++ -O2 -o test-thread test-thread.cpp -lboost_thread-gcc-mt-s -lpthread
./test-thread
Segmentation fault
Wer weiß, was könnte der Grund sein?
Hier ist der Code verwende ich:
#include <boost/thread.hpp>
#include <boost/function.hpp>
void task1() {
// do something
}
void task2() {
// do something
}
int main (int argc, char ** argv) {
using namespace boost;
function0<void> f1(&task1);
function0<void> f2(&task2);
thread thread_1(f1);
thread thread_2(f2);
// do other stuff
thread_2.join();
thread_1.join();
return 0;
}
P. S .: Ich benutze Boost 1.32 auf Ubuntu Linux.
UPDATE:
Hier ist, wo es im Debugger stürzt (wo die Leitung 37 den mit thread_2.join();
in meinem ursprünglichen Code ist):
(gdb) bt
#0 0x080499e0 in boost::thread::join ()
#1 0x080496b8 in main (argc=1, argv=0xbfea3eb4) at ../src/test-thread.cpp:37
Hier sind meine eigentlichen zwei Funktionen:
void task1() {
std::cerr << "THREAD 1 START" << std::endl;
for(double i=0; i<999999; ++i){
std::cout << i << std::endl;
}
std::cerr << "THREAD 1 END" << std::endl;
}
void task2() {
std::cerr << "THREAD 2 START" << std::endl;
for(double i=0; i<999999; ++i){
std::cout << i << std::endl;
}
std::cerr << "THREAD 2 END" << std::endl;
}
Vielen Dank für jede Hilfe!
Lösung 2
fand ich den Fehler! Ich hatte gegen die falsche Version der Bibliothek verknüpft. Ich hatte boost_thread-gcc-mt-s
gewesen verwendet, aber es funktioniert mit boost_thread-gcc-mt
statt:
g++ -O2 -o test-thread test-thread.cpp -lboost_thread-gcc-mt -lpthread
schaute ich in die Boost-Dokumentation, aber ich konnte keine Informationen über nicht finden, was die Unterschiede zwischen diesen Bibliotheksversionen sind. Es gibt auch eine boost_thread-gcc-mt-d
, die ich davon ausgehen, ist die Debug-Version, aber die Verknüpfung gegen das man immer zu Binärdateien, die segfault, selbst wenn sie mit -g
kompilieren. Aber zumindest kann ich jetzt die Fäden laufen.
Andere Tipps
Könnten Sie sicher, dass Core-Dumps aktiv sind (ulimit -c unlimited
), kompilieren mit Symbolen (-O2 -g) laufen, und öffnen Sie die Stack-Trace in gdb? (gdb test-thread core
, geben Sie dann backtrace
an der gdb
Aufforderung quit
zu beenden)
UPDATE
Auf der Grundlage der Backtrace, die Segmentierungsfehler tritt in
boost::thread::join
. Könntest du wieder öffnen, die den Kern und:
- eine Zerlegung des
boost::thread::join
Verfahren erhalten:
disassemble boost::thread::join
disassemble
- einen Dump des Registers erhalten:
info registers
Die Umsetzung der
boost::thread::join
(Boost 1,32 offizielle Quelle) ist ziemlich geradlinig, so es sei denn, die Ubuntu Binärdateien grob divergieren von der offizieller Code (die wir hoffentlich von der Demontage herausfinden), gibt es nur zwei Mögliche Ursachen für die Segmentierung bemängeln.Können Sie bestätigen auch, wie weit in ihren Ausdrucken die beiden Fäden vor dem Segmentierungsfehler haben?
void thread::join() { int res = 0; #if defined(BOOST_HAS_WINTHREADS) res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE); assert(res == WAIT_OBJECT_0); res = CloseHandle(reinterpret_cast<HANDLE>(m_thread)); assert(res); #elif defined(BOOST_HAS_PTHREADS) res = pthread_join(m_thread, 0); assert(res == 0); #elif defined(BOOST_HAS_MPTASKS) OSStatus lStatus = threads::mac::detail::safe_wait_on_queue( m_pJoinQueueID, NULL, NULL, NULL, kDurationForever); assert(lStatus == noErr); #endif // This isn't a race condition since any race that could occur would // have us in undefined behavior territory any way. m_joinable = false; }
Übliche Ursachen für diese Art von Problemen:
- nicht initialisierten Variablen
- Variablen, die von beiden Threads zugegriffen werden, die nicht markiert
volatile
wurden - inlined Anrufe und / oder abgerollt Schleifen (deren Stapelrahmengröße ist die Summe aller inlined Stack-Frames Methode Instanzen) rekursiv aufgerufen wird und die überquellenden Stapel viel schneller als die nicht-inlined Versionen