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

Leave a Reply