boost :: rosca: Segfault ao executar versão otimizada
-
05-09-2019 - |
Pergunta
Eu tenho problemas para obter boost:thread
ao trabalho. Ele funciona muito bem quando compilar sem otimização:
g++ -o test-thread test-thread.cpp -lboost_thread-gcc-mt-s -lpthread
./test-thread
Mas uma versão que é compilado com otimizações acidentes
g++ -O2 -o test-thread test-thread.cpp -lboost_thread-gcc-mt-s -lpthread
./test-thread
Segmentation fault
Alguém sabe o que pode ser a razão?
Aqui está o código que estou usando:
#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 .: Eu estou usando boost 1,32 no Ubuntu Linux.
UPDATE:
Aqui é onde ele trava no depurador (onde a linha 37 é o único com thread_2.join();
no meu código original):
(gdb) bt
#0 0x080499e0 in boost::thread::join ()
#1 0x080496b8 in main (argc=1, argv=0xbfea3eb4) at ../src/test-thread.cpp:37
Aqui estão as minhas reais duas funções:
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;
}
Obrigado por qualquer ajuda!
Solução 2
Eu encontrei o bug! Eu tinha ligado contra a versão errada da biblioteca. Eu tinha sido usando boost_thread-gcc-mt-s
, mas funciona com boost_thread-gcc-mt
vez:
g++ -O2 -o test-thread test-thread.cpp -lboost_thread-gcc-mt -lpthread
Eu olhei para a documentação impulso, mas eu não poderia encontrar qualquer informação sobre o que as diferenças entre essas versões da biblioteca estão. Há também um boost_thread-gcc-mt-d
, que eu suponho que é a versão de depuração, mas que liga contra o que sempre resulta em binários que segfault, mesmo quando compilando com -g
. Mas pelo menos eu posso correr os fios agora.
Outras dicas
Você poderia ter certeza de que descarregar um core são ativos (ulimit -c unlimited
), compilação com símbolos (-O2 -g), Executar e abrir o rastreamento de pilha no gdb? (gdb test-thread core
, em seguida, digite backtrace
no gdb
alerta, quit
parar)
Atualizar
Com base no registo de chamadas, o falha de segmentação ocorre em
boost::thread::join
. Você poderia re-abrir o núcleo e:
- obter uma desmontagem do método
boost::thread::join
:
disassemble boost::thread::join
disassemble
- obter um despejo dos registros:
info registers
A implementação de
boost::thread::join
(boost 1,32 fonte oficial) é bastante straight-forward, então a menos que o Ubuntu binários grosseiramente divergir do código oficial (que nós esperamos descobrir a partir do desmontagem), existem apenas dois possíveis causas para a segmentação falha.Pode também confirmar o quão longe em suas impressões os dois tópicos tem antes da falha de segmentação?
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; }
causas usuais para esses tipos de problemas:
- variáveis ??não inicializadas
- variáveis ??que são acessados ??por ambos os tópicos que não foram marcados
volatile
- chamadas e / ou loops desenroladas (cuja pilha tamanho do quadro é a soma dos quadros de pilha todas as instâncias do método sequenciais) que está sendo chamado de forma recursiva e transbordando a pilha muito mais rápido do que as versões não-inline inline