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