This is a sweet spot of thread functionality for me at the moment, mixing boost and c++11, so I’m throwing it down here. It’s also in my Reusable code on git.
// --------------------------------------------------------------------
// CONCISE EXAMPLE OF THREAD WITH EXTERNALLY-ACCESSIBLE STATUS AND DATA
// --------------------------------------------------------------------
// We create a vector, and create a thread to start stuffing it.
// Externally, we can check the status of the job, and have mutex access to the data.
// The atomic job stage is SO CHEAP to change and check, do it all day long as needed.
// Initially, externally, we check the job stage.
// Meanwhile, we do a bunch of intense work inside the mutex.
// Then we do smaller work with frequent mutexing, allowing interruption.
// Great patterns, use them brother!
// Hells to the yeah.
// --------------------------------------------------------------------
std::atomic<int32_t> job_stage(0);
std::unordered_set<int> data;
boost::shared_mutex data_guard;
data.insert(-1);
std::thread t([&job_stage,&data,&data_guard] {
// stage 1 = jam in data
job_stage = 1;
{
boost::upgrade_lock<boost::shared_mutex> lock(data_guard);
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
for (int loop = 0; loop < 2000; ++loop)
{
std::this_thread::sleep_for(1ms);
data.insert(loop);
}
}
// stage 2 = mutex-jam data, allowing intervention
job_stage = 2;
for (int loop = 3000000; loop < 4000000 && job_stage == 2; ++loop)
{
boost::upgrade_lock<boost::shared_mutex> lock(data_guard);
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
data.insert(loop);
}
cout << "thread exiting..." << endl;
});
cout << "pre mutex job stage: " << job_stage << endl;
for (int check = 0; check < 5; ++check)
{
std::this_thread::sleep_for(200ms);
// not sure why i was getting std::hex output...
cout << "check " << check << " job stage: ";
{
boost::upgrade_lock<boost::shared_mutex> lock(data_guard);
cout << dec << job_stage << " data size " << data.size();
}
cout << endl;
}
// We can trigger the thread to exit.
job_stage = 3;
// Let's see what happens if we don't join until after the thread is done.
std::this_thread::sleep_for(300ms);
cout << "done sleeping" << endl;
// NOW we will block to ensure the thread finishes.
cout << "joining" << endl;
t.join();
cout << "all done" << endl;
// --------------------------------------------------------------------
Output:
pre mutex job stage: 1
check 0 job stage: 2 data size 2031
check 1 job stage: 2 data size 225848
check 2 job stage: 2 data size 456199
check 3 job stage: 2 data size 726576
check 4 job stage: 2 data size 936429
thread exiting...
check 5 job stage: 2 data size 1002001
done sleeping
joining
all done