Skip to content

Instantly share code, notes, and snippets.

@facontidavide
Created January 9, 2019 11:03
Show Gist options
  • Save facontidavide/2315cd32ca39bd186083e004f0882a33 to your computer and use it in GitHub Desktop.
Save facontidavide/2315cd32ca39bd186083e004f0882a33 to your computer and use it in GitHub Desktop.
This simple multithreading C++ may sometimes crash (SIGSEGV) or remain blocked forever inside waitStart. Can you figure out why?
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
// The purpose of the this apparently fine application is to make you appreciate thread santizers
// https://clang.llvm.org/docs/ThreadSanitizer.html
class Foo{
public:
Foo(): _start_requested(false), _stop_requested(false), _thread( &Foo::loop, this )
{}
void loop()
{
while(!_stop_requested)
{
waitStart();
std::cout << "loop" << std::endl;
std::this_thread::sleep_for( std::chrono::milliseconds(200) );
}
}
void waitStart()
{
std::unique_lock<std::mutex> lock(_mutex);
while( !_start_requested )
{
_start_signaler.wait(lock);
}
}
void startLoop()
{
std::unique_lock<std::mutex> lock(_mutex);
_start_requested = true;
_start_signaler.notify_all();
}
void stopLoop()
{
_stop_requested = true;
_thread.join();
}
private:
std::atomic_bool _start_requested;
std::atomic_bool _stop_requested;
std::thread _thread;
std::mutex _mutex;
std::condition_variable _start_signaler;
};
int main()
{
Foo foo;
foo.startLoop();
std::this_thread::sleep_for( std::chrono::seconds(1) );
foo.stopLoop();
return 0;
}
@Anghan15
Copy link

As class members are initialized in the order in which they are declared in the class, not the order in which they appear in the class initializer list, _thread is initialized before _mutex. When the thread procedure, loop(), is invocated, _mutex may Not have been initialized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment