libmoost
/home/mhx/git/github/libmoost/test/pdl/test_multithread.cpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #include <csignal>
00029 #include <vector>
00030 #include <string>
00031 
00032 #include <boost/test/unit_test.hpp>
00033 #include <boost/thread.hpp>
00034 #include <boost/bind.hpp>
00035 
00036 #include "../../include/moost/pdl/dynamic_library.h"
00037 #include "../../include/moost/safe_shared_ptr.hpp"
00038 
00039 #include "test_interface.h"
00040 
00041 BOOST_AUTO_TEST_SUITE(moost_pdl_multithread)
00042 
00043 namespace
00044 {
00045 
00046 // mmmmh, maybe we can turn this into a stand-alone template?
00047 template <typename T>
00048 class atomic
00049 {
00050 public:
00051    atomic()
00052       : m_value(0)
00053    {
00054    }
00055 
00056    atomic& operator++ ()
00057    {
00058       atomic_add_and_fetch(1);
00059       return *this;
00060    }
00061 
00062    T read()
00063    {
00064       return atomic_add_and_fetch(0);
00065    }
00066 
00067 private:
00068    volatile T m_value;
00069 
00070 #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
00071    T atomic_add_and_fetch(T x)
00072    {
00073       return __sync_add_and_fetch(&m_value, x);
00074    }
00075 #else
00076    boost::mutex m_mutex;
00077 
00078    T atomic_add_and_fetch(T x)
00079    {
00080       boost::mutex::scoped_lock lock(m_mutex);
00081       m_value += x;
00082       return m_value;
00083    }
00084 #endif
00085 };
00086 
00087 atomic<unsigned> c3_load;
00088 atomic<unsigned> c3_unload;
00089 atomic<unsigned> c3_ctor;
00090 atomic<unsigned> c3_dtor;
00091 
00092 atomic<unsigned> c4_load;
00093 atomic<unsigned> c4_unload;
00094 atomic<unsigned> c4_ctor;
00095 atomic<unsigned> c4_dtor;
00096 
00097 class multithread_pdl_test
00098 {
00099 public:
00100    multithread_pdl_test(const std::vector<std::string>& libs)
00101       : m_finish(0)
00102       , m_lib_counter(0)
00103       , m_libs(libs)
00104    {
00105       reload(true);
00106    }
00107 
00108    void reload(bool force)
00109    {
00110       if (force)
00111       {
00112          m_dl.open(m_libs[m_lib_counter++ % m_libs.size()]);
00113       }
00114 
00115       m_inst = m_dl.create<my_test_interface>("my_test_class");
00116    }
00117 
00118    void process()
00119    {
00120       boost::shared_ptr<my_test_interface> inst = m_inst.get_shared();
00121 
00122       for (size_t i = 0; i < 10; ++i)
00123       {
00124          inst->do_it();
00125       }
00126    }
00127 
00128    void processor_thread()
00129    {
00130       while (!m_finish)
00131       {
00132          process();
00133       }
00134    }
00135 
00136    void run(size_t num_threads = 37)
00137    {
00138       boost::thread_group tg;
00139 
00140       for (size_t i = 0; i < num_threads; ++i)
00141       {
00142          tg.create_thread(boost::bind(&multithread_pdl_test::processor_thread, this));
00143       }
00144 
00145       for (size_t i = 0; i < 2000; ++i)
00146       {
00147          boost::this_thread::sleep(boost::posix_time::microseconds(500));
00148          reload(i % 5 == 0);
00149       }
00150 
00151       m_finish = 1;
00152 
00153       tg.join_all();
00154    }
00155 
00156 private:
00157    volatile sig_atomic_t m_finish;
00158    size_t m_lib_counter;
00159    std::vector<std::string> m_libs;
00160    moost::pdl::dynamic_library m_dl;
00161    moost::safe_shared_ptr<my_test_interface> m_inst;
00162 };
00163 
00164 }
00165 
00166 extern "C" void pdl_test_c3_load() { ++c3_load; }
00167 extern "C" void pdl_test_c3_unload() { ++c3_unload; }
00168 extern "C" void pdl_test_c3_ctor() { ++c3_ctor; }
00169 extern "C" void pdl_test_c3_dtor() { ++c3_dtor; }
00170 
00171 extern "C" void pdl_test_c4_load() { ++c4_load; }
00172 extern "C" void pdl_test_c4_unload() { ++c4_unload; }
00173 extern "C" void pdl_test_c4_ctor() { ++c4_ctor; }
00174 extern "C" void pdl_test_c4_dtor() { ++c4_dtor; }
00175 
00176 BOOST_AUTO_TEST_CASE(pdl_thread)
00177 {
00178    // Check behaviour in a multi-threaded environment
00179 
00180    std::vector<std::string> libs;
00181 
00182    libs.push_back("../lib/test_module3");
00183    libs.push_back("../lib/test_module4");
00184 
00185    multithread_pdl_test(libs).run();
00186 
00187    BOOST_CHECK(c3_load.read() > 0);
00188    BOOST_CHECK(c3_ctor.read() > 0);
00189 
00190    BOOST_CHECK(c4_load.read() > 0);
00191    BOOST_CHECK(c4_ctor.read() > 0);
00192 
00193    BOOST_CHECK_EQUAL(c3_load.read(), c3_unload.read());
00194    BOOST_CHECK_EQUAL(c3_ctor.read(), c3_dtor.read());
00195 
00196    BOOST_CHECK_EQUAL(c4_load.read(), c4_unload.read());
00197    BOOST_CHECK_EQUAL(c4_ctor.read(), c4_dtor.read());
00198 }
00199 
00200 BOOST_AUTO_TEST_SUITE_END()