Parcourir la source

Multithreading tests

Eric Ramat il y a 10 ans
Parent
commit
6f5885e0ab

+ 3 - 2
CMakeLists.txt

@@ -49,7 +49,7 @@ INCLUDE(CMakeCPack.cmake)
 
 IF (CMAKE_COMPILER_IS_GNUCC AND CMAKE_COMPILER_IS_GNUCXX)
   SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
-  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -std=c++11")
+  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -std=c++11 -pthread")
   IF (UNIX)
     SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic")
     SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
@@ -97,7 +97,7 @@ ENDIF (WIN32)
 SET(Boost_DETAILED_FAILURE_MSG FALSE)
 SET(Boost_DEBUG FALSE)
 
-FIND_PACKAGE(Boost COMPONENTS graph)
+FIND_PACKAGE(Boost COMPONENTS graph timer system)
 IF (NOT Boost_GRAPH_FOUND)
   MESSAGE(FATAL_ERROR "The boost graph library is required")
 ENDIF (NOT Boost_GRAPH_FOUND)
@@ -161,6 +161,7 @@ MESSAGE(STATUS "- - - -")
 MESSAGE(STATUS "${PARADEVS_NAME_COMPLETE} configured successfully")
 MESSAGE(STATUS "Using ${CMAKE_INSTALL_PREFIX} for installation")
 MESSAGE(STATUS "Build type ${CMAKE_BUILD_TYPE}")
+MESSAGE(STATUS "Boost timer = ${Boost_TIMER_LIBRARY}")
 IF (PARADEVS_HAVE_GCC_ABI_DEMANGLE)
   MESSAGE(STATUS "Build with GCC ABI Demangle...: yes")
 ENDIF (PARADEVS_HAVE_GCC_ABI_DEMANGLE)

BIN
doc/comparison.ods


+ 2 - 4
src/apps/CMakeLists.txt

@@ -14,9 +14,7 @@ ADD_EXECUTABLE(paradevs main.cpp ${MIXED_TESTS_HPP})
 SET_TARGET_PROPERTIES(paradevs PROPERTIES ${PARADEVS_APP_PROPERTIES})
 
 TARGET_LINK_LIBRARIES(paradevs
-  ${GLIBMM_LIBRARIES}
-  ${LIBXML_LIBRARIES}
-  ${GTHREAD_LIBRARIES}
-  ${Boost_FILESYSTEM_LIBRARY})
+  ${Boost_SYSTEM_LIBRARY}
+  ${Boost_TIMER_LIBRARY})
 
 INSTALL(TARGETS paradevs DESTINATION bin)

+ 45 - 359
src/apps/main.cpp

@@ -24,7 +24,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <boost/timer.hpp>
+#include <boost/timer/timer.hpp>
 
 #include <common/RootCoordinator.hpp>
 #include <common/scheduler/VectorScheduler.hpp>
@@ -40,7 +40,7 @@ using namespace paradevs::tests::mixed;
 template < int size >
 void run_flat_with_heap()
 {
-    boost::timer t;
+    boost::timer::cpu_timer t;
 
     std::cout << "run_flat_with_heap [" << size << "] ..." << std::endl;
 
@@ -57,13 +57,13 @@ void run_flat_with_heap()
     paradevs::common::Trace < paradevs::common::DoubleTime >::trace().clear();
     rc.run();
 
-    std::cout << "... OK -> " << t.elapsed() << std::endl;
+    std::cout << "... OK -> " << t.elapsed().user << std::endl;
 }
 
 template < int size >
 void run_flat_with_vector()
 {
-    boost::timer t;
+    boost::timer::cpu_timer t;
 
     std::cout << "run_flat_with_vector [" << size << "] ..." << std::endl;
 
@@ -81,7 +81,7 @@ void run_flat_with_vector()
     paradevs::common::Trace < paradevs::common::DoubleTime >::trace().clear();
     rc.run();
 
-    std::cout << "... OK -> " << t.elapsed() << std::endl;
+    std::cout << "... OK -> " << t.elapsed().user << std::endl;
 }
 
 void run_hierarchic_with_heap()
@@ -116,362 +116,48 @@ void run_hierarchic_with_vector()
     rc.run();
 }
 
-// int main()
-// {
-//     boost::timer t;
-
-//     srand(108364);
-
-//     run_flat_with_heap < 10 >();
-//     run_flat_with_heap < 20 >();
-//     run_flat_with_heap < 30 >();
-//     run_flat_with_heap < 40 >();
-//     run_flat_with_heap < 50 >();
-//     run_flat_with_heap < 60 >();
-//     run_flat_with_heap < 70 >();
-//     run_flat_with_heap < 80 >();
-//     run_flat_with_heap < 90 >();
-//     run_flat_with_heap < 100 >();
-//     run_flat_with_heap < 200 >();
-
-//     run_flat_with_vector < 10 >();
-//     run_flat_with_vector < 20 >();
-//     run_flat_with_vector < 30 >();
-//     run_flat_with_vector < 40 >();
-//     run_flat_with_vector < 50 >();
-//     run_flat_with_vector < 60 >();
-//     run_flat_with_vector < 70 >();
-//     run_flat_with_vector < 80 >();
-//     run_flat_with_vector < 90 >();
-//     run_flat_with_vector < 100 >();
-//     run_flat_with_vector < 200 >();
-
-//     double t2 = t.elapsed();
-
-//     std::cout << "run_hierarchic_with_heap ..." << std::endl;
-//     run_hierarchic_with_heap();
-
-//     double t3 = t.elapsed();
-
-//     std::cout << "... OK -> " << (t3 - t2) << std::endl;
-//     std::cout << "run_hierarchic_with_vector ..." << std::endl;
-//     run_hierarchic_with_vector();
-
-//     double t4 = t.elapsed();
-
-//     std::cout << "... OK -> "  << (t4 - t3) << std::endl;
-//     return 0;
-// }
-
-#include <condition_variable>
-#include <queue>
-#include <memory>
-#include <mutex>
-#include <thread>
-
-namespace messaging {
-
-    struct message_base
-    {
-        virtual ~message_base()
-        {}
-    };
-
-    template < typename Msg >
-    struct wrapped_message : message_base
-    {
-        Msg contents;
-
-        explicit wrapped_message(Msg const& contents_) : contents(contents_)
-        { }
-    };
-
-    class queue
-    {
-    public:
-        template < typename T >
-        void push(T const& msg)
-        {
-            std::lock_guard < std::mutex > lk(m);
-
-            q.push(std::make_shared < wrapped_message < T > >(msg));
-            c.notify_all();
-        }
-
-        std::shared_ptr < message_base > wait_and_pop()
-        {
-            std::unique_lock < std::mutex > lk(m);
-
-            c.wait(lk, [&]{ return !q.empty(); });
-            auto res = q.front();
-            q.pop();
-            return res;
-        }
-
-    private:
-        std::mutex m;
-        std::condition_variable c;
-        std::queue < std::shared_ptr < message_base > > q;
-    };
-
-    class close_queue
-    { };
-
-    class sender
-    {
-    public:
-        sender() : q(nullptr)
-        { }
-
-        explicit sender(queue* q_) : q(q_)
-        { }
-
-        template < typename Message >
-        void send(Message const& msg)
-        {
-            if (q) {
-                q->push(msg);
-            }
-        }
-
-    private:
-        queue* q;
-    };
-
-    template < typename PreviousDispatcher, typename Msg, typename Func >
-    class TemplateDispatcher
-    {
-    public:
-        TemplateDispatcher(TemplateDispatcher&& other) : q(other.q),
-                                                         prev(other.prev),
-                                                         f(std::move(other.f)),
-                                                         chained(other.chained)
-        {
-            other.chained = true;
-        }
-
-        TemplateDispatcher(queue* q_, PreviousDispatcher* prev_, Func&& f_) :
-            q(q_), prev(prev_), f(std::forward < Func >(f_)), chained(false)
-        {
-            prev_->chained = true;
-        }
-
-        template < typename OtherMsg,
-                   typename OtherFunc >
-        TemplateDispatcher < TemplateDispatcher, OtherMsg, OtherFunc >
-        handle(OtherFunc&& of)
-        {
-            return TemplateDispatcher<
-                TemplateDispatcher, OtherMsg, OtherFunc>(
-                    q, this, std::forward < OtherFunc >(of));
-        }
-
-        ~TemplateDispatcher() noexcept(false)
-        {
-            if (!chained) {
-                wait_and_dispatch();
-            }
-        }
-
-    private:
-        TemplateDispatcher(TemplateDispatcher const&)=delete;
-
-        TemplateDispatcher& operator=(TemplateDispatcher const&)=delete;
-
-        template <typename Dispatcher, typename OtherMsg, typename OtherFunc >
-        friend class TemplateDispatcher;
-
-        void wait_and_dispatch()
-        {
-            for(;;) {
-                auto msg = q->wait_and_pop();
-
-                if (dispatch(msg)) {
-                    break;
-                }
-            }
-        }
-
-        bool dispatch(std::shared_ptr < message_base > const& msg)
-        {
-            if (wrapped_message < Msg >* wrapper =
-                dynamic_cast < wrapped_message < Msg >* >(msg.get())) {
-                f(wrapper->contents);
-                return true;
-            } else {
-                return prev->dispatch(msg);
-            }
-        }
-
-        queue* q;
-        PreviousDispatcher* prev;
-        Func f;
-        bool chained;
-    };
-
-    class dispatcher
-    {
-    public:
-        dispatcher(dispatcher&& other) : q(other.q), chained(other.chained)
-        {
-            other.chained = true;
-        }
-
-        explicit dispatcher(queue* q_) : q(q_), chained(false)
-        {}
-
-        template < typename Message, typename Func >
-        TemplateDispatcher < dispatcher, Message, Func >
-        handle(Func&& f)
-        {
-            return TemplateDispatcher < dispatcher, Message, Func >(
-                q, this, std::forward < Func >(f));
-        }
-
-        ~dispatcher() noexcept(false)
-        {
-            if (!chained) {
-                wait_and_dispatch();
-            }
-        }
-
-    private:
-        dispatcher(dispatcher const&)=delete;
-
-        dispatcher& operator=(dispatcher const&)=delete;
-
-        template<
-            typename Dispatcher,
-            typename Msg,
-            typename Func>
-        friend class TemplateDispatcher;
-
-        void wait_and_dispatch()
-        {
-            for(;;) {
-                auto msg = q->wait_and_pop();
-
-                dispatch(msg);
-            }
-        }
-
-        bool dispatch(std::shared_ptr < message_base > const& msg)
-        {
-            if (dynamic_cast < wrapped_message < close_queue >* >(msg.get())) {
-                throw close_queue();
-            }
-            return false;
-        }
-
-        queue* q;
-        bool chained;
-    };
-
-    class receiver
-    {
-    public:
-        operator sender()
-        {
-            return sender(&q);
-        }
-
-        dispatcher wait()
-        {
-            return dispatcher(&q);
-        }
-
-    private:
-        queue q;
-    };
-
-} // namespace messaging
-
-struct start
-{ };
-
-struct my_message
-{ };
-
-class A
-{
-public:
-    A(messaging::sender b_) : b(b_)
-    { }
-
-    void done()
-    { get_sender().send(messaging::close_queue()); }
-
-    messaging::sender get_sender()
-    { return incoming; }
-
-    void run()
-    {
-        try
-        {
-            for(;;) {
-                incoming.wait().handle < start >(
-                    [&](start const& /* msg */)
-                    {
-                        std::cout << "start" << std::endl;
-                        b.send(my_message());
-                    }
-                    );;
-            }
-        }
-        catch(messaging::close_queue const&)
-        { }
-    }
-
-private:
-    messaging::receiver incoming;
-    messaging::sender b;
-};
-
-class B
-{
-public:
-    B()
-    { }
-
-    void done()
-    { get_sender().send(messaging::close_queue()); }
-
-    messaging::sender get_sender()
-    { return incoming; }
-
-    void run()
-    {
-        try
-        {
-            for(;;) {
-                incoming.wait().handle < my_message >(
-                    [&](my_message const& /* msg */)
-                    { std::cout << "receive my message" << std::endl; }
-                    );
-            }
-        }
-        catch(messaging::close_queue const&)
-        { }
-    }
-
-private:
-    messaging::receiver incoming;
-};
-
 int main()
 {
-    B b;
-    A a(b.get_sender());
-
-    std::thread A_thread(&A::run, &a);
-    std::thread B_thread(&B::run, &b);
-
-    a.get_sender().send(start());
-    sleep(1);
+    srand(108364);
+
+    run_flat_with_heap < 10 >();
+    run_flat_with_heap < 20 >();
+    run_flat_with_heap < 30 >();
+    run_flat_with_heap < 40 >();
+    run_flat_with_heap < 50 >();
+    run_flat_with_heap < 60 >();
+    run_flat_with_heap < 70 >();
+    run_flat_with_heap < 80 >();
+    run_flat_with_heap < 90 >();
+    run_flat_with_heap < 100 >();
+    run_flat_with_heap < 200 >();
+
+    run_flat_with_vector < 10 >();
+    run_flat_with_vector < 20 >();
+    run_flat_with_vector < 30 >();
+    run_flat_with_vector < 40 >();
+    run_flat_with_vector < 50 >();
+    run_flat_with_vector < 60 >();
+    run_flat_with_vector < 70 >();
+    run_flat_with_vector < 80 >();
+    run_flat_with_vector < 90 >();
+    run_flat_with_vector < 100 >();
+    run_flat_with_vector < 200 >();
+
+    double t2 = t.elapsed();
+
+    std::cout << "run_hierarchic_with_heap ..." << std::endl;
+    run_hierarchic_with_heap();
+
+    double t3 = t.elapsed();
+
+    std::cout << "... OK -> " << (t3 - t2) << std::endl;
+    std::cout << "run_hierarchic_with_vector ..." << std::endl;
+    run_hierarchic_with_vector();
+
+    double t4 = t.elapsed();
+
+    std::cout << "... OK -> "  << (t4 - t3) << std::endl;
 
-    a.done();
-    b.done();
-    A_thread.join();
-    B_thread.join();
     return 0;
 }

+ 1 - 1
src/common/utils/CMakeLists.txt

@@ -10,7 +10,7 @@ LINK_DIRECTORIES(
   ${LIBXML_LIBRARY_DIR}
   ${Boost_LIBRARY_DIRS})
 
-SET(COMMON_UTILS_HPP String.hpp Trace.hpp)
+SET(COMMON_UTILS_HPP Multithreading.hpp String.hpp Trace.hpp)
 
 INSTALL(FILES ${COMMON_UTILS_HPP} DESTINATION
   ${PARADEVS_INCLUDE_DIRS}/common/utils)

+ 250 - 0
src/common/utils/Multithreading.hpp

@@ -0,0 +1,250 @@
+/**
+ * @file common/utils/Multithreading.hpp
+ * @author The PARADEVS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * PARADEVS - the multimodeling and simulation environment
+ * This file is a part of the PARADEVS environment
+ *
+ * Copyright (C) 2013 ULCO http://www.univ-litoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef COMMON_UTILS_MULTITHREADING
+#define COMMON_UTILS_MULTITHREADING 1
+
+#include <condition_variable>
+#include <queue>
+#include <mutex>
+
+namespace paradevs { namespace common {
+
+struct BaseMessage
+{
+    virtual ~BaseMessage()
+    { }
+};
+
+template < typename Msg >
+struct Message : BaseMessage
+{
+    explicit Message(Msg const& content) : _content(content)
+    { }
+
+    Msg _content;
+};
+
+class Close
+{ };
+
+class MessageQueue
+{
+public:
+    template < typename T >
+    void push(T const& msg)
+    {
+        std::lock_guard < std::mutex > lock(_mutex);
+
+        _queue.push(std::make_shared < Message < T > >(msg));
+        _condition.notify_all();
+    }
+
+    std::shared_ptr < BaseMessage > wait_and_pop()
+    {
+        std::unique_lock < std::mutex > lock(_mutex);
+
+        _condition.wait(lock, [&]{ return not _queue.empty(); });
+        auto res = _queue.front();
+        _queue.pop();
+        return res;
+    }
+
+private:
+    std::mutex                                     _mutex;
+    std::condition_variable                        _condition;
+    std::queue < std::shared_ptr < BaseMessage > > _queue;
+};
+
+class Sender
+{
+public:
+    Sender() : _queue(0)
+    { }
+
+    explicit Sender(MessageQueue* queue) : _queue(queue)
+    { }
+
+    template < typename Message >
+    void send(Message const& msg)
+    {
+        if (_queue) {
+            _queue->push(msg);
+        }
+    }
+
+private:
+    MessageQueue* _queue;
+};
+
+template < typename PreviousDispatcher, typename Msg, typename Func >
+class TemplateDispatcher
+{
+    template < typename Dispatcher, typename OtherMsg, typename OtherFunc >
+    friend class TemplateDispatcher;
+
+public:
+    TemplateDispatcher(TemplateDispatcher&& other) : _queue(other._queue),
+                                                     _previous(other._previous),
+                                                     _function(
+                                                         std::move(
+                                                             other._function)),
+                                                     _chained(other._chained)
+    { other._chained = true; }
+
+    TemplateDispatcher(MessageQueue* queue,
+                       PreviousDispatcher* previous,
+                       Func&& function) :
+        _queue(queue), _previous(previous),
+        _function(std::forward < Func >(function)), _chained(false)
+    { previous->_chained = true; }
+
+    bool dispatch(std::shared_ptr < BaseMessage > const& msg)
+    {
+        Message < Msg >* message =
+            dynamic_cast < Message < Msg >* >(msg.get());
+
+        if (message) {
+            _function(message->_content);
+            return true;
+        } else {
+            return _previous->dispatch(msg);
+        }
+    }
+
+    template < typename OtherMsg, typename OtherFunc >
+    TemplateDispatcher < TemplateDispatcher < PreviousDispatcher, Msg, Func >,
+                         OtherMsg, OtherFunc >
+    handle(OtherFunc&& of)
+    {
+        return TemplateDispatcher < TemplateDispatcher < PreviousDispatcher,
+                                                         Msg, Func >,
+                                    OtherMsg, OtherFunc >(
+            _queue, this, std::forward < OtherFunc >(of));
+    }
+
+    ~TemplateDispatcher() noexcept(false)
+    {
+        if (not _chained) {
+            wait_and_dispatch();
+        }
+    }
+
+private:
+    TemplateDispatcher(TemplateDispatcher const&)=delete;
+
+    TemplateDispatcher& operator=(TemplateDispatcher const&)=delete;
+
+    void wait_and_dispatch()
+    {
+        for(;;) {
+            auto msg = _queue->wait_and_pop();
+
+            if (dispatch(msg)) {
+                break;
+            }
+        }
+    }
+
+    MessageQueue*       _queue;
+    PreviousDispatcher* _previous;
+    Func                _function;
+    bool                _chained;
+};
+
+class Dispatcher
+{
+    template < typename Dispatcher, typename Msg, typename Func>
+    friend class TemplateDispatcher;
+
+public:
+    Dispatcher(Dispatcher&& other) : _queue(other._queue),
+                                     _chained(other._chained)
+    { other._chained = true; }
+
+    explicit Dispatcher(MessageQueue* queue) : _queue(queue), _chained(false)
+    { }
+
+    template < typename Message, typename Func >
+    TemplateDispatcher < Dispatcher, Message, Func >
+    handle(Func&& function)
+    {
+        return TemplateDispatcher < Dispatcher, Message, Func >(
+            _queue, this, std::forward < Func >(function));
+    }
+
+    ~Dispatcher() noexcept(false)
+    {
+        if (not _chained) {
+            wait_and_dispatch();
+        }
+    }
+
+private:
+    Dispatcher(Dispatcher const&)=delete;
+
+    Dispatcher& operator=(Dispatcher const&)=delete;
+
+    void wait_and_dispatch()
+    {
+        for(;;) {
+            auto msg = _queue->wait_and_pop();
+
+            dispatch(msg);
+        }
+    }
+
+    bool dispatch(std::shared_ptr < BaseMessage > const& msg)
+    {
+        if (dynamic_cast < Message < Close >* >(msg.get())) {
+            throw Close();
+        }
+        return false;
+    }
+
+    MessageQueue* _queue;
+    bool          _chained;
+};
+
+class Receiver
+{
+public:
+    Receiver()
+    { }
+
+    operator Sender()
+    { return Sender(&_queue); }
+
+    Dispatcher wait()
+    { return Dispatcher(&_queue); }
+
+private:
+    MessageQueue _queue;
+};
+
+} }  // namespace paradevs common
+
+#endif

+ 3 - 3
src/common/utils/String.hpp

@@ -1,5 +1,5 @@
 /**
- * @file String.hpp
+ * @file common/utils/String.hpp
  * @author The PARADEVS Development Team
  * See the AUTHORS or Authors.txt file
  */
@@ -24,8 +24,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef COMMON_STRING
-#define COMMON_STRING 1
+#ifndef COMMON_UTILS_STRING
+#define COMMON_UTILS_STRING 1
 
 #include <string>
 

+ 2 - 2
src/common/utils/Trace.hpp

@@ -24,8 +24,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef COMMON_TRACE
-#define COMMON_TRACE 1
+#ifndef COMMON_UTILS_TRACE
+#define COMMON_UTILS_TRACE 1
 
 #include <algorithm>
 #include <iterator>

+ 2 - 2
src/kernel/pdevs/GraphManager.hpp

@@ -147,11 +147,11 @@ public:
     {
     	std::ostringstream ss;
 
-    	/*ss << common::spaces(level * 2) << "Childs :" << std::endl;
+    	ss << common::spaces(level * 2) << "Childs :" << std::endl;
         for (auto & child : _child_list) {
             ss << child->to_string(level + 1);
         }
-        ss << _link_list.to_string(level);*/
+        ss << _link_list.to_string(level);
         return ss.str();
     }
 

+ 138 - 74
src/kernel/pdevs/multithreading/Coordinator.hpp

@@ -27,58 +27,55 @@
 #ifndef PDEVS_MULTITHREADING_COORDINATOR
 #define PDEVS_MULTITHREADING_COORDINATOR 1
 
+#include <common/utils/Multithreading.hpp>
 #include <kernel/pdevs/Coordinator.hpp>
 
-#include <future>
+#include <thread>
 
 namespace paradevs { namespace pdevs { namespace multithreading {
 
-class Barrier
+template < class Time>
+struct start_message
 {
-    struct SubBarrier
-    {
-        std::condition_variable _cv;
-        std::mutex              _lck;
-        int                     _runners;
-    };
+    explicit start_message(typename Time::type t) : _t(t)
+    { }
 
-public:
-    Barrier(int count) : _max(count)
-    {
-        _current = &_sub_barriers[0];
-        for (int i = 0; i < 2; ++i) {
-            _sub_barriers[i]._runners = count;
-        }
-    }
+    typename Time::type _t;
+};
 
-    virtual ~Barrier()
+template < class Time>
+struct transition_message
+{
+    explicit transition_message(typename Time::type t) : _t(t)
     { }
 
-    int wait()
-    {
-        SubBarrier *sub_barrier = _current;
+    typename Time::type _t;
+};
 
-        std::unique_lock < std::mutex > lck(sub_barrier->_lck);
+template < class Time, class SchedulerHandle >
+struct done_start_message
+{
+    explicit done_start_message(typename Time::type tn,
+                                common::Model < Time,
+                                                SchedulerHandle >* child) :
+        _tn(tn), _child(child)
+    { }
 
-        if (sub_barrier->_runners == 1) {
-            if (_max != 1) {
-                sub_barrier->_runners = _max;
-                _current = (_current == &_sub_barriers[0]) ? &_sub_barriers[1] :
-                    &_sub_barriers[0];
-                sub_barrier->_cv.notify_all();
-            }
-        } else {
-            sub_barrier->_runners--;
-            while (sub_barrier->_runners != _max)
-                sub_barrier->_cv.wait(lck);
-        }
-        return 0;
-    }
+    typename Time::type                      _tn;
+    common::Model < Time, SchedulerHandle >* _child;
+};
 
-private:
-    int         _max;
-    SubBarrier  _sub_barriers[2];
-    SubBarrier* _current;
+template < class Time, class SchedulerHandle >
+struct done_transition_message
+{
+    explicit done_transition_message(typename Time::type tn,
+                                     common::Model < Time,
+                                                     SchedulerHandle >* child) :
+        _tn(tn), _child(child)
+    { }
+
+    typename Time::type                      _tn;
+    common::Model < Time, SchedulerHandle >* _child;
 };
 
 template < class Time,
@@ -95,6 +92,12 @@ class Coordinator : public pdevs::Coordinator < Time, Scheduler,
                                  Parameters, GraphParameters > parent_type;
     typedef Coordinator < Time, Scheduler, SchedulerHandle, GraphManager,
                           Parameters, GraphParameters > type;
+    typedef done_start_message < Time,
+                                 SchedulerHandle > done_start_message_type;
+    typedef start_message < Time > start_message_type;
+    typedef done_transition_message < Time,
+                                 SchedulerHandle > done_transition_message_type;
+    typedef transition_message < Time > transition_message_type;
 
 public:
     Coordinator(const std::string& name,
@@ -102,70 +105,131 @@ public:
                 const GraphParameters& graph_parameters) :
         pdevs::Coordinator < Time, Scheduler, SchedulerHandle, GraphManager,
                              Parameters, GraphParameters >(name, parameters,
-                                                           graph_parameters)
-    {
-        for (auto & child : parent_type::_graph_manager.children()) {
-            if (not child->is_atomic()) {
-                type* coordinator = dynamic_cast < type* >(child);
+                                                           graph_parameters),
+        _thread(std::thread([&]{ loop(); }))
+    { type::_graph_manager.init(); }
 
-                _threads.push_back(std::thread([&]{ coordinator->loop(); }));
-            }
-        }
+    virtual ~Coordinator()
+    {
+        done();
+        _thread.join();
     }
 
-    virtual ~Coordinator()
-    { }
+    void done()
+    { get_sender().send(paradevs::common::Close()); }
 
-    void loop()
-    {
-        bool stop = false;
+    paradevs::common::Sender get_sender()
+    { return _incoming; }
 
-        while (not stop) {
+    void set_sender(common::Sender sender)
+    { _sender = sender; }
 
+    void loop()
+    {
+        try
+        {
+            for(;;) {
+                _incoming.wait()
+                    .template handle < start_message_type >(
+                        [&](start_message_type const& msg)
+                        {
+                            typename Time::type tn = start(msg._t);
+                            _sender.send(done_start_message_type(tn, this));
+                        })
+                    .template handle < done_start_message_type >(
+                        [&](done_start_message_type const& msg)
+                        {
+                            type::_event_table.init(msg._tn, msg._child);
+                            --_received;
+                            if (_received == 0) {
+                                _received_mutex.unlock();
+                            }
+                        })
+                    .template handle < transition_message_type >(
+                        [&](transition_message_type const& msg)
+                        {
+                            typename Time::type tn = transition(msg._t);
+                            _sender.send(done_transition_message_type(tn,
+                                                                      this));
+                        })
+                    .template handle < done_transition_message_type >(
+                        [&](done_transition_message_type const& msg)
+                        {
+                            type::_event_table.put(msg._tn, msg._child);
+                            --_received;
+                            if (_received == 0) {
+                                _received_mutex.unlock();
+                            }
+                        });
+            }
         }
+        catch(paradevs::common::Close const&)
+        { }
     }
 
     typename Time::type start(typename Time::type t)
     {
+        _received = 0;
         for (auto & child : parent_type::_graph_manager.children()) {
             if (child->is_atomic()) {
                 type::_event_table.init(child->start(type::_tn), child);
             } else {
-
+                ++_received;
             }
         }
+
+        if (_received > 0) {
+            type::_graph_manager.start(t);
+            _received_mutex.lock();
+
+            std::lock_guard < std::mutex > lock(_received_mutex);
+
+        }
+
         type::_tl = t;
         type::_tn = type::_event_table.get_current_time();
         return type::_tn;
     }
 
-    void output(typename Time::type t)
-    {
-        parent_type::output(t);
-    }
-
     typename Time::type transition(typename Time::type t)
     {
-        return parent_type::transition(t);
-    }
+        assert(t >= type::_tl and t <= type::_tn);
 
-    void post_event(typename Time::type t,
-                    const common::ExternalEvent < Time,
-                                                  SchedulerHandle >& event)
-    {
-         parent_type::post_event(t, event);
-    }
+        common::Models < Time, SchedulerHandle > receivers =
+            type::_event_table.get_current_models(t);
 
-    typename Time::type dispatch_events(
-        common::Bag < Time, SchedulerHandle > bag, typename Time::type t)
-    {
-        return parent_type::dispatch_events(bag, t);
+        type::add_models_with_inputs(receivers);
+
+        _received = 0;
+        for (auto & model : receivers) {
+            if (model->is_atomic()) {
+                type::_event_table.put(model->transition(t), model);
+            } else {
+                ++_received;
+            }
+        }
+
+        if (_received > 0) {
+            type::_graph_manager.transition(receivers, t);
+            _received_mutex.lock();
+
+            std::lock_guard < std::mutex > lock(_received_mutex);
+
+        }
+
+        parent_type::update_event_table(t);
+        type::_tl = t;
+        type::_tn = type::_event_table.get_current_time();
+        type::clear_bag();
+        return type::_tn;
     }
 
 private:
-    typedef std::vector < std::thread > Threads;
-
-    Threads _threads;
+    std::thread                _thread;
+    paradevs::common::Receiver _incoming;
+    paradevs::common::Sender   _sender;
+    unsigned int               _received;
+    std::mutex                 _received_mutex;
 };
 
 } } } // namespace paradevs pdevs multithreading

+ 2 - 3
src/tests/multithreading/CMakeLists.txt

@@ -15,6 +15,5 @@ SET_TARGET_PROPERTIES(pdevs-multithreading-tests PROPERTIES
   ${PARADEVS_APP_PROPERTIES})
 
 TARGET_LINK_LIBRARIES(pdevs-multithreading-tests
-  ${GLIBMM_LIBRARIES}
-  ${LIBXML_LIBRARIES}
-  ${GTHREAD_LIBRARIES})
+  ${Boost_SYSTEM_LIBRARY}
+  ${Boost_TIMER_LIBRARY})

+ 248 - 0
src/tests/multithreading/graph_manager.hpp

@@ -63,6 +63,18 @@ public:
                                                      coordinator, "out");
     }
 
+    void init()
+    { }
+
+    void start(common::DoubleTime::type /* t */)
+    { }
+
+    void transition(
+        const common::Models < common::DoubleTime,
+                               pdevs::SchedulerHandle >& /* receivers */,
+        common::DoubleTime::type /* t */)
+    { }
+
     virtual ~S1GraphManager()
     { }
 
@@ -102,6 +114,18 @@ public:
                                                      &a, "in");
     }
 
+    void init()
+    { }
+
+    void start(common::DoubleTime::type /* t */)
+    { }
+
+    void transition(
+        const common::Models < common::DoubleTime,
+                               pdevs::SchedulerHandle >& /* receivers */,
+        common::DoubleTime::type /* t */)
+    { }
+
     virtual ~S2GraphManager()
     { }
 
@@ -137,6 +161,54 @@ public:
         add_link(&S1, "out", &S2, "in");
     }
 
+    void init()
+    {
+        S1.set_sender(
+            dynamic_cast < paradevs::pdevs::multithreading::Coordinator <
+                common::DoubleTime,
+                paradevs::common::scheduler::HeapScheduler <
+                    common::DoubleTime, pdevs::SchedulerHandle >,
+                pdevs::SchedulerHandle,
+                paradevs::tests::multithreading::RootGraphManager >*
+            >(get_coordinator())->get_sender());
+        S2.set_sender(
+            dynamic_cast < paradevs::pdevs::multithreading::Coordinator <
+                common::DoubleTime,
+                paradevs::common::scheduler::HeapScheduler <
+                    common::DoubleTime, pdevs::SchedulerHandle >,
+                pdevs::SchedulerHandle,
+                paradevs::tests::multithreading::RootGraphManager >*
+            >(get_coordinator())->get_sender());
+    }
+
+    void start(common::DoubleTime::type t)
+    {
+        S1.get_sender().send(
+            paradevs::pdevs::multithreading::start_message <
+                common::DoubleTime >(t));
+        S2.get_sender().send(
+            paradevs::pdevs::multithreading::start_message <
+                common::DoubleTime >(t));
+    }
+
+    void transition(const common::Models < common::DoubleTime,
+                                           pdevs::SchedulerHandle >& receivers,
+                    common::DoubleTime::type t)
+    {
+        if (std::find(receivers.begin(), receivers.end(),
+                      &S1) != receivers.end()) {
+            S1.get_sender().send(
+                paradevs::pdevs::multithreading::transition_message <
+                    common::DoubleTime >(t));
+        }
+        if (std::find(receivers.begin(), receivers.end(),
+                      &S2) != receivers.end()) {
+            S2.get_sender().send(
+                paradevs::pdevs::multithreading::transition_message <
+                    common::DoubleTime >(t));
+        }
+    }
+
     virtual ~RootGraphManager()
     { }
 
@@ -153,6 +225,182 @@ private:
         S2GraphManager < pdevs::SchedulerHandle > > S2;
 };
 
+template < class SchedulerHandle >
+class S3GraphManager :
+        public paradevs::pdevs::GraphManager < common::DoubleTime,
+                                               SchedulerHandle >
+{
+public:
+    S3GraphManager(common::Coordinator < common::DoubleTime,
+                                         SchedulerHandle >* coordinator,
+                   const paradevs::common::NoParameters& parameters) :
+        paradevs::pdevs::GraphManager < common::DoubleTime,
+                                        SchedulerHandle >(coordinator,
+                                                          parameters)
+    {
+        coordinator->add_out_port("out");
+        for (unsigned int i = 0; i < 10; ++i) {
+            std::ostringstream ss;
+            simulator_type* s = new simulator_type(ss.str(),
+                                                   common::NoParameters());
+
+            ss << "a" << (i + 1);
+            _simulators.push_back(s);
+            S3GraphManager < SchedulerHandle >::add_child(s);
+            s->add_out_port("out");
+        }
+    }
+
+    void init()
+    { }
+
+    void start(common::DoubleTime::type /* t */)
+    { }
+
+    void transition(
+        const common::Models < common::DoubleTime,
+                               pdevs::SchedulerHandle >& /* receivers */,
+        common::DoubleTime::type /* t */)
+    { }
+
+    virtual ~S3GraphManager()
+    {
+        for (typename std::vector < simulator_type* >::const_iterator it =
+                 _simulators.begin(); it != _simulators.end(); ++it) {
+            delete *it;
+        }
+    }
+
+private:
+    typedef paradevs::pdevs::Simulator < common::DoubleTime,
+                                         pdevs::A < SchedulerHandle >,
+                                         SchedulerHandle > simulator_type;
+
+    std::vector < simulator_type* > _simulators;
+};
+
+class Root2GraphManager :
+        public paradevs::pdevs::GraphManager < common::DoubleTime,
+                                               pdevs::SchedulerHandle >
+{
+public:
+    Root2GraphManager(
+        common::Coordinator < common::DoubleTime,
+                              pdevs::SchedulerHandle >* coordinator,
+        const paradevs::common::NoParameters& parameters) :
+        paradevs::pdevs::GraphManager < common::DoubleTime,
+                                        pdevs::SchedulerHandle >(
+                                            coordinator, parameters),
+        S1("S1", paradevs::common::NoParameters(),
+           paradevs::common::NoParameters()),
+        S2("S2", paradevs::common::NoParameters(),
+           paradevs::common::NoParameters())
+    {
+        add_child(&S1);
+        add_child(&S2);
+    }
+
+    void init()
+    {
+        S1.set_sender(
+            dynamic_cast < paradevs::pdevs::multithreading::Coordinator <
+                common::DoubleTime,
+                paradevs::common::scheduler::HeapScheduler <
+                    common::DoubleTime, pdevs::SchedulerHandle >,
+                pdevs::SchedulerHandle,
+                paradevs::tests::multithreading::Root2GraphManager >*
+            >(get_coordinator())->get_sender());
+        S2.set_sender(
+            dynamic_cast < paradevs::pdevs::multithreading::Coordinator <
+                common::DoubleTime,
+                paradevs::common::scheduler::HeapScheduler <
+                    common::DoubleTime, pdevs::SchedulerHandle >,
+                pdevs::SchedulerHandle,
+                paradevs::tests::multithreading::Root2GraphManager >*
+            >(get_coordinator())->get_sender());
+    }
+
+    void start(common::DoubleTime::type t)
+    {
+        S1.get_sender().send(
+            paradevs::pdevs::multithreading::start_message <
+                common::DoubleTime >(t));
+        S2.get_sender().send(
+            paradevs::pdevs::multithreading::start_message <
+                common::DoubleTime >(t));
+    }
+
+    void transition(const common::Models < common::DoubleTime,
+                                           pdevs::SchedulerHandle >& receivers,
+                    common::DoubleTime::type t)
+    {
+        if (std::find(receivers.begin(), receivers.end(),
+                      &S1) != receivers.end()) {
+            S1.get_sender().send(
+                paradevs::pdevs::multithreading::transition_message <
+                    common::DoubleTime >(t));
+        }
+        if (std::find(receivers.begin(), receivers.end(),
+                      &S2) != receivers.end()) {
+            S2.get_sender().send(
+                paradevs::pdevs::multithreading::transition_message <
+                    common::DoubleTime >(t));
+        }
+    }
+
+    virtual ~Root2GraphManager()
+    { }
+
+private:
+    paradevs::pdevs::multithreading::Coordinator <
+        common::DoubleTime,
+        pdevs::SchedulerType,
+        pdevs::SchedulerHandle,
+        S3GraphManager < pdevs::SchedulerHandle > > S1;
+    paradevs::pdevs::multithreading::Coordinator <
+        common::DoubleTime,
+        pdevs::SchedulerType,
+        pdevs::SchedulerHandle,
+        S3GraphManager < pdevs::SchedulerHandle > > S2;
+};
+
+class Root3GraphManager :
+        public paradevs::pdevs::GraphManager < common::DoubleTime,
+                                               pdevs::SchedulerHandle >
+{
+public:
+    Root3GraphManager(
+        common::Coordinator < common::DoubleTime,
+                              pdevs::SchedulerHandle >* coordinator,
+        const paradevs::common::NoParameters& parameters) :
+        paradevs::pdevs::GraphManager < common::DoubleTime,
+                                        pdevs::SchedulerHandle >(
+                                            coordinator, parameters),
+        S1("S1", paradevs::common::NoParameters(),
+           paradevs::common::NoParameters()),
+        S2("S2", paradevs::common::NoParameters(),
+           paradevs::common::NoParameters())
+    {
+        add_child(&S1);
+        add_child(&S2);
+    }
+
+    virtual ~Root3GraphManager()
+    { }
+
+private:
+    paradevs::pdevs::Coordinator <
+        common::DoubleTime,
+        pdevs::SchedulerType,
+        pdevs::SchedulerHandle,
+        S3GraphManager < pdevs::SchedulerHandle > > S1;
+    paradevs::pdevs::Coordinator <
+        common::DoubleTime,
+        pdevs::SchedulerType,
+        pdevs::SchedulerHandle,
+        S3GraphManager < pdevs::SchedulerHandle > > S2;
+};
+
 } } } // namespace paradevs tests multithreading
 
 #endif

+ 89 - 3
src/tests/multithreading/tests.cpp

@@ -25,20 +25,24 @@
  */
 
 #include <tests/multithreading/graph_manager.hpp>
-#include <tests/pdevs/models.hpp>
 #include <tests/pdevs/graph_manager.hpp>
 
 #include <common/RootCoordinator.hpp>
 
+#include <chrono>
+
 #define CATCH_CONFIG_MAIN
 #include <tests/catch.hpp>
 
 using namespace paradevs::tests::pdevs;
 using namespace paradevs::tests::multithreading;
 using namespace paradevs::common;
+using namespace std::chrono;
 
-TEST_CASE("pdevs/hierachical", "run")
+TEST_CASE("pdevs/multithreading/hierachical", "run")
 {
+    steady_clock::time_point t1 = steady_clock::now();
+
     paradevs::common::RootCoordinator <
         DoubleTime, paradevs::pdevs::multithreading::Coordinator <
             DoubleTime,
@@ -46,8 +50,90 @@ TEST_CASE("pdevs/hierachical", "run")
                 DoubleTime, SchedulerHandle >,
             SchedulerHandle,
             paradevs::tests::multithreading::RootGraphManager >
-        > rc(0, 10000, "root", paradevs::common::NoParameters(),
+        > rc(0, 100, "root", paradevs::common::NoParameters(),
+             paradevs::common::NoParameters());
+
+    rc.run();
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration < double > time_span = duration_cast <
+        duration < double > >(t2 - t1);
+
+    std::cout << "multithreading/dependant -> " << time_span.count()
+              << std::endl;
+}
+
+TEST_CASE("pdevs/classic/hierachical", "run")
+{
+    steady_clock::time_point t1 = steady_clock::now();
+
+    paradevs::common::RootCoordinator <
+        DoubleTime, paradevs::pdevs::Coordinator <
+            DoubleTime,
+            paradevs::common::scheduler::HeapScheduler <
+                DoubleTime, SchedulerHandle >,
+            SchedulerHandle,
+            paradevs::tests::pdevs::RootGraphManager >
+        > rc(0, 100, "root", paradevs::common::NoParameters(),
+             paradevs::common::NoParameters());
+
+    rc.run();
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration < double > time_span = duration_cast <
+        duration < double > >(t2 - t1);
+
+    std::cout << "classic/dependant -> " << time_span.count() << std::endl;
+}
+
+TEST_CASE("pdevs/multithreading/independant", "run")
+{
+    steady_clock::time_point t1 = steady_clock::now();
+
+    paradevs::common::RootCoordinator <
+        DoubleTime, paradevs::pdevs::multithreading::Coordinator <
+            DoubleTime,
+            paradevs::common::scheduler::HeapScheduler <
+                DoubleTime, SchedulerHandle >,
+            SchedulerHandle,
+            paradevs::tests::multithreading::Root2GraphManager >
+        > rc(0, 100, "root", paradevs::common::NoParameters(),
+             paradevs::common::NoParameters());
+
+    rc.run();
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration < double > time_span = duration_cast <
+        duration < double > >(t2 - t1);
+
+    std::cout << "multithreading/independant -> " << time_span.count()
+              << std::endl;
+}
+
+TEST_CASE("pdevs/classic/independant", "run")
+{
+    steady_clock::time_point t1 = steady_clock::now();
+
+    paradevs::common::RootCoordinator <
+        DoubleTime, paradevs::pdevs::Coordinator <
+            DoubleTime,
+            paradevs::common::scheduler::HeapScheduler <
+                DoubleTime, SchedulerHandle >,
+            SchedulerHandle,
+            paradevs::tests::multithreading::Root3GraphManager >
+        > rc(0, 100, "root", paradevs::common::NoParameters(),
              paradevs::common::NoParameters());
 
     rc.run();
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration < double > time_span = duration_cast <
+        duration < double > >(t2 - t1);
+
+    std::cout << "classic/independant -> " << time_span.count() << std::endl;
 }
+

+ 2 - 3
src/tests/pdevs/CMakeLists.txt

@@ -14,6 +14,5 @@ ADD_EXECUTABLE(pdevs-tests ${COMMON_HPP} ${COMMON_SCHEDULER_HPP} ${PDEVS_HPP}
 SET_TARGET_PROPERTIES(pdevs-tests PROPERTIES ${PARADEVS_APP_PROPERTIES})
 
 TARGET_LINK_LIBRARIES(pdevs-tests
-  ${GLIBMM_LIBRARIES}
-  ${LIBXML_LIBRARIES}
-  ${GTHREAD_LIBRARIES})
+  ${Boost_SYSTEM_LIBRARY}
+  ${Boost_TIMER_LIBRARY})

+ 20 - 0
src/tests/pdevs/models.hpp

@@ -32,8 +32,24 @@
 
 #include <kernel/pdevs/Dynamics.hpp>
 
+#include <chrono>
+
+#define DELAY 100
+
 namespace paradevs { namespace tests { namespace pdevs {
 
+void delay()
+{
+    for (unsigned int i = 0; i < DELAY; ++i) {
+        std::vector < int > v;
+
+        for (unsigned int j = 1000; j > 0; --j) {
+            v.push_back(j);
+        }
+        std::sort(v.begin(), v.end());
+    }
+}
+
 template < class SchedulerHandle>
 class A :
         public paradevs::pdevs::Dynamics < common::DoubleTime, SchedulerHandle >
@@ -61,6 +77,8 @@ public:
         common::Trace < common::DoubleTime >::trace().flush();
 #endif
 
+        delay();
+
         if (_phase == SEND) {
             _phase = WAIT;
         }
@@ -211,6 +229,8 @@ public:
         common::Trace < common::DoubleTime >::trace().flush();
 #endif
 
+        delay();
+
         if (_phase == SEND) {
             _phase = WAIT;
         }