leponceau.org

Programming And Stuff, You Know The Thing…

C++0x, Boost v1.53 And Thread Concurrency

Posted at — Mar 11, 2013

Just tested 3 thread synchronization methods on a multi-cpu machine:

# I'm using Boost v1.53 on Ubunt 12.04.01 LTS/amd64
# (download the package, run "./bootstrap.sh --prefix=$prefix; ./b2 -q -j4 install")
c++ -O3 -fPIC -std=c++0x -fpermissive -pthread -Wall -Wl,-rpath=$prefix/lib -I$prefix/include -o boost_threads_atomic_test_case.bin boost_threads_atomic_test_case.cpp -L$prefix/lib -lboost_unit_test_framework -lboost_filesystem -lboost_chrono -lboost_thread -lboost_system  -lpthread -lrt
#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>

#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <vector>
#include <iostream>
#include <atomic>

namespace {

    // Shared variables for generation barrier test
    const int N_THREADS = 10;
    const long N_PER_THREAD = 10000000;
    boost::mutex mutex;
    std::atomic<long> global_parameter{0};

    void barrier_thread() {
//        boost::thread::id tid = boost::this_thread::get_id();
        long todo = N_PER_THREAD;
        while(todo > 0) {
//            std::cout << tid << "  lock(mutex)" << std::endl;
            //boost::unique_lock<boost::mutex> lock(mutex);
//            std::cout << global_parameter << "  " << tid << "  global_parameter++" << std::endl;
            global_parameter++;
            todo--;
        }
    }

} // namespace

BOOST_AUTO_TEST_CASE(test) {
    boost::thread_group g;
    global_parameter = 0;

    try {
        for (int i = 0; i < N_THREADS; ++i)
            g.create_thread(&amp;barrier_thread);
        g.join_all();
    } catch (...) {
        g.interrupt_all();
        g.join_all();
        throw;
    }

    BOOST_CHECK_EQUAL(global_parameter, N_THREADS * N_PER_THREAD);
}
#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>

#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <vector>
#include <iostream>

namespace {

    // Shared variables for generation barrier test
    const int N_THREADS = 10;
    const long N_PER_THREAD = 1000000;
    boost::mutex mutex;
    volatile long global_parameter;

    void barrier_thread() {
//        boost::thread::id tid = boost::this_thread::get_id();
        long todo = N_PER_THREAD;
        while(todo > 0) {
//            std::cout << tid << "  lock(mutex)" << std::endl;
            boost::unique_lock<boost::mutex> lock(mutex);
//            std::cout << global_parameter << "  " << tid << "  global_parameter++" << std::endl;
            global_parameter++;
            todo--;
        }
    }

} // namespace

BOOST_AUTO_TEST_CASE(test) {
    boost::thread_group g;
    global_parameter = 0;

    try {
        for (int i = 0; i < N_THREADS; ++i)
            g.create_thread(&amp;barrier_thread);
        g.join_all();
    } catch (...) {
        g.interrupt_all();
        g.join_all();
        throw;
    }

    BOOST_CHECK_EQUAL(global_parameter, N_THREADS * N_PER_THREAD);
}
/**
 * Runs into a deadlock.
 */

#define BOOST_TEST_MODULE example
#include <boost/test/included/unit_test.hpp>

#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/barrier.hpp>
#include <vector>
#include <iostream>

namespace {

    // Shared variables for generation barrier test
    const int N_THREADS = 10;
    const long N_PER_THREAD = 100;
    boost::barrier gen_barrier(N_THREADS);
    boost::mutex mutex;
    volatile long global_parameter;

    void barrier_thread() {
        boost::thread::id tid = boost::this_thread::get_id();
        long todo = N_PER_THREAD;
        while(todo > 0) {
            std::cout << tid << "  gen_barrier.wait()" << std::endl;
            // this causes deadlocks...
            if (gen_barrier.wait()) {
                std::cout << tid << "  lock(mutex)" << std::endl;
                boost::unique_lock<boost::mutex> lock(mutex);
                std::cout << global_parameter << "  " << tid << "  global_parameter++" << std::endl;
                global_parameter++;
                todo--;
            }
        }
    }

} // namespace

BOOST_AUTO_TEST_CASE(test) {
    boost::thread_group g;
    global_parameter = 0;

    std::cerr << "skipping this test case because it is deadlock prone" << std::endl;
    return;
    
    try {
        for (int i = 0; i < N_THREADS; ++i)
            g.create_thread(&amp;barrier_thread);
        g.join_all();
    } catch (...) {
        g.interrupt_all();
        g.join_all();
        throw;
    }

    BOOST_CHECK_EQUAL(global_parameter, N_THREADS * N_PER_THREAD);
}