Commit c6b558b1 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

* Introduced check whether signal emitting thread is the signal manager...

* Introduced check whether signal emitting thread is the signal manager thread. In such a case signals are now emitted synchronously per default.
* Fixed sigslot shared library builds

refs #384
parent fd355fdf
...@@ -27,6 +27,10 @@ ENDIF() ...@@ -27,6 +27,10 @@ ENDIF()
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs}) INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs})
TARGET_LINK_LIBRARIES(sigslot tgt) TARGET_LINK_LIBRARIES(sigslot tgt)
# if campvis-core is built as a shared library, CMake will define the following flag to instruct
# the code to export DLL symbols
SET_TARGET_PROPERTIES(sigslot PROPERTIES DEFINE_SYMBOL "SIGSLOT_BUILD_DLL")
################################################################################ ################################################################################
# deployment # deployment
################################################################################ ################################################################################
......
...@@ -26,6 +26,7 @@ namespace sigslot { ...@@ -26,6 +26,7 @@ namespace sigslot {
} }
void signal_manager::run() { void signal_manager::run() {
_this_thread_id = std::this_thread::get_id();
std::unique_lock<tbb::mutex> lock(_ecMutex); std::unique_lock<tbb::mutex> lock(_ecMutex);
while (! _stopExecution) { while (! _stopExecution) {
...@@ -47,6 +48,10 @@ namespace sigslot { ...@@ -47,6 +48,10 @@ namespace sigslot {
tgt::Runnable::stop(); tgt::Runnable::stop();
} }
bool signal_manager::isCurrentThreadSignalManagerThread() const {
return std::this_thread::get_id() == _this_thread_id;
}
const std::string signal_manager::loggerCat_; const std::string signal_manager::loggerCat_;
......
...@@ -90,6 +90,29 @@ ...@@ -90,6 +90,29 @@
#ifndef SIGSLOT_H #ifndef SIGSLOT_H
#define SIGSLOT_H #define SIGSLOT_H
#ifdef CAMPVIS_DYNAMIC_LIBS
#ifdef SIGSLOT_BUILD_DLL
// building library -> export symbols
#ifdef WIN32
#define SIGSLOT_API __declspec(dllexport)
#else
#define SIGSLOT_API
#endif
#else
// including library -> import symbols
#ifdef WIN32
#define SIGSLOT_API __declspec(dllimport)
#else
#define SIGSLOT_API
#endif
#endif
#else
// building/including static library -> do nothing
#define SIGSLOT_API
#endif
#include <set> #include <set>
#include <list> #include <list>
...@@ -110,15 +133,30 @@ ...@@ -110,15 +133,30 @@
namespace sigslot { namespace sigslot {
/// Base class for signal handles that provides an interface to emit the signal.
class _signal_handle_base { class _signal_handle_base {
public: public:
/// Virtual destructor
virtual ~_signal_handle_base() {}; virtual ~_signal_handle_base() {};
/// Emits the signal of this signal handle.
virtual void emitSignal() const = 0; virtual void emitSignal() const = 0;
}; };
// ================================================================================================ // ================================================================================================
class signal_manager : public tgt::Singleton<signal_manager>, public tgt::Runnable { /**
* Singleton class that takes care of queuing and asynchronously dispatching signals.
*
* The signal_manager implements the Runnable interface, i.e. runs in it's own thread once it
* was launched. The signal_manager takes care of dispatching signals to their connections.
* This is either done synchrnously by using triggerSignal() or asynchronously by using
* queueSignal(). Furthermore it allows to check, whether the current thread is the
* signal_manager thread. This allows the default signal emitting method operator() to
* automatically decide on the dispatch type based on the emitting thread.
*
* signal_manager can be considered as thread-safe.
*/
class SIGSLOT_API signal_manager : public tgt::Singleton<signal_manager>, public tgt::Runnable {
friend class tgt::Singleton<signal_manager>; friend class tgt::Singleton<signal_manager>;
public: public:
...@@ -138,6 +176,12 @@ namespace sigslot { ...@@ -138,6 +176,12 @@ namespace sigslot {
*/ */
bool queueSignal(_signal_handle_base* signal); bool queueSignal(_signal_handle_base* signal);
/**
* Checks whether calling thread is signal_manager thread.
* \return std::this_thread::get_id() == _this_thread_id
*/
bool isCurrentThreadSignalManagerThread() const;
/// \see Runnable:run /// \see Runnable:run
virtual void run(); virtual void run();
/// \see Runnable:stop /// \see Runnable:stop
...@@ -149,6 +193,7 @@ namespace sigslot { ...@@ -149,6 +193,7 @@ namespace sigslot {
/// Private destructor only for singleton /// Private destructor only for singleton
~signal_manager(); ~signal_manager();
/// Typedef for the signal queue
typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue; typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;
SignalQueue _signalQueue; ///< Queue for signals to be dispatched SignalQueue _signalQueue; ///< Queue for signals to be dispatched
...@@ -156,6 +201,8 @@ namespace sigslot { ...@@ -156,6 +201,8 @@ namespace sigslot {
std::condition_variable _evaluationCondition; ///< conditional wait to be used when there are currently no jobs to process std::condition_variable _evaluationCondition; ///< conditional wait to be used when there are currently no jobs to process
tbb::mutex _ecMutex; ///< Mutex for protecting _evaluationCondition tbb::mutex _ecMutex; ///< Mutex for protecting _evaluationCondition
std::thread::id _this_thread_id;
static const std::string loggerCat_; static const std::string loggerCat_;
}; };
...@@ -1303,17 +1350,25 @@ namespace sigslot { ...@@ -1303,17 +1350,25 @@ namespace sigslot {
pclass->signal_connect(this); pclass->signal_connect(this);
} }
void emitSignal() void trigger()
{ {
signal_handle0* sh = new signal_handle0(this); signal_handle0* sh = new signal_handle0(this);
signal_manager::getRef().triggerSignal(sh); signal_manager::getRef().triggerSignal(sh);
} }
void operator()() void queue()
{ {
signal_handle0* sh = new signal_handle0(this); signal_handle0* sh = new signal_handle0(this);
signal_manager::getRef().queueSignal(sh); signal_manager::getRef().queueSignal(sh);
} }
void operator()()
{
if (signal_manager::getRef().isCurrentThreadSignalManagerThread())
trigger();
else
queue();
}
}; };
template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> template<class arg1_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
...@@ -1366,17 +1421,25 @@ namespace sigslot { ...@@ -1366,17 +1421,25 @@ namespace sigslot {
pclass->signal_connect(this); pclass->signal_connect(this);
} }
void emitSignal(arg1_type a1) void trigger(arg1_type a1)
{ {
signal_handle1* sh = new signal_handle1(this, a1); signal_handle1* sh = new signal_handle1(this, a1);
signal_manager::getRef().triggerSignal(sh); signal_manager::getRef().triggerSignal(sh);
} }
void operator()(arg1_type a1) void queue(arg1_type a1)
{ {
signal_handle1* sh = new signal_handle1(this, a1); signal_handle1* sh = new signal_handle1(this, a1);
signal_manager::getRef().queueSignal(sh); signal_manager::getRef().queueSignal(sh);
} }
void operator()(arg1_type a1)
{
if (signal_manager::getRef().isCurrentThreadSignalManagerThread())
trigger(a1);
else
queue(a1);
}
}; };
template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> template<class arg1_type, class arg2_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
...@@ -1432,17 +1495,25 @@ namespace sigslot { ...@@ -1432,17 +1495,25 @@ namespace sigslot {
pclass->signal_connect(this); pclass->signal_connect(this);
} }
void emitSignal(arg1_type a1, arg2_type a2) void trigger(arg1_type a1, arg2_type a2)
{ {
signal_handle2* sh = new signal_handle2(this, a1, a2); signal_handle2* sh = new signal_handle2(this, a1, a2);
signal_manager::getRef().triggerSignal(sh); signal_manager::getRef().triggerSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2) void queue(arg1_type a1, arg2_type a2)
{ {
signal_handle2* sh = new signal_handle2(this, a1, a2); signal_handle2* sh = new signal_handle2(this, a1, a2);
signal_manager::getRef().queueSignal(sh); signal_manager::getRef().queueSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2)
{
if (signal_manager::getRef().isCurrentThreadSignalManagerThread())
trigger(a1, a2);
else
queue(a1, a2);
}
}; };
template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> template<class arg1_type, class arg2_type, class arg3_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
...@@ -1500,17 +1571,25 @@ namespace sigslot { ...@@ -1500,17 +1571,25 @@ namespace sigslot {
pclass->signal_connect(this); pclass->signal_connect(this);
} }
void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3) void trigger(arg1_type a1, arg2_type a2, arg3_type a3)
{ {
signal_handle3* sh = new signal_handle3(this, a1, a2, a3); signal_handle3* sh = new signal_handle3(this, a1, a2, a3);
signal_manager::getRef().triggerSignal(sh); signal_manager::getRef().triggerSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2, arg3_type a3) void queue(arg1_type a1, arg2_type a2, arg3_type a3)
{ {
signal_handle3* sh = new signal_handle3(this, a1, a2, a3); signal_handle3* sh = new signal_handle3(this, a1, a2, a3);
signal_manager::getRef().queueSignal(sh); signal_manager::getRef().queueSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2, arg3_type a3)
{
if (signal_manager::getRef().isCurrentThreadSignalManagerThread())
trigger(a1, a2, a3);
else
queue(a1, a2, a3);
}
}; };
template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
...@@ -1570,17 +1649,25 @@ namespace sigslot { ...@@ -1570,17 +1649,25 @@ namespace sigslot {
pclass->signal_connect(this); pclass->signal_connect(this);
} }
void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) void trigger(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
{ {
signal_handle4* sh = new signal_handle4(this, a1, a2, a3, a4); signal_handle4* sh = new signal_handle4(this, a1, a2, a3, a4);
signal_manager::getRef().triggerSignal(sh); signal_manager::getRef().triggerSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4) void queue(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
{ {
signal_handle4* sh = new signal_handle4(this, a1, a2, a3, a4); signal_handle4* sh = new signal_handle4(this, a1, a2, a3, a4);
signal_manager::getRef().queueSignal(sh); signal_manager::getRef().queueSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4)
{
if (signal_manager::getRef().isCurrentThreadSignalManagerThread())
trigger(a1, a2, a3, a4);
else
queue(a1, a2, a3, a4);
}
}; };
template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> template<class arg1_type, class arg2_type, class arg3_type, class arg4_type, class arg5_type, class mt_policy = SIGSLOT_DEFAULT_MT_POLICY>
...@@ -1642,17 +1729,25 @@ namespace sigslot { ...@@ -1642,17 +1729,25 @@ namespace sigslot {
pclass->signal_connect(this); pclass->signal_connect(this);
} }
void emitSignal(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) void trigger(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5)
{ {
signal_handle5* sh = new signal_handle5(this, a1, a2, a3, a4, a5); signal_handle5* sh = new signal_handle5(this, a1, a2, a3, a4, a5);
signal_manager::getRef().triggerSignal(sh); signal_manager::getRef().triggerSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5) void queue(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5)
{ {
signal_handle5* sh = new signal_handle5(this, a1, a2, a3, a4, a5); signal_handle5* sh = new signal_handle5(this, a1, a2, a3, a4, a5);
signal_manager::getRef().queueSignal(sh); signal_manager::getRef().queueSignal(sh);
} }
void operator()(arg1_type a1, arg2_type a2, arg3_type a3, arg4_type a4, arg5_type a5)
{
if (signal_manager::getRef().isCurrentThreadSignalManagerThread())
trigger(a1, a2, a3, a4, a5);
else
queue(a1, a2, a3, a4, a5);
}
}; };
} // namespace sigslot } // namespace sigslot
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <ext/threading.h> #include <ext/threading.h>
#include <tbb/atomic.h> #include <tbb/atomic.h>
#include "core/coreapi.h"
namespace tgt { namespace tgt {
/** /**
...@@ -38,7 +37,7 @@ namespace tgt { ...@@ -38,7 +37,7 @@ namespace tgt {
* in the run() method which has to be overwritten in subclasses. Calling stop() sets _stopExecution to true * in the run() method which has to be overwritten in subclasses. Calling stop() sets _stopExecution to true
* and waits for the thread to finish. Hence, you should test for _stopExecution in your run() method. * and waits for the thread to finish. Hence, you should test for _stopExecution in your run() method.
*/ */
class CAMPVIS_CORE_API Runnable { class TGT_API Runnable {
public: public:
/** /**
* Creates a new Runnable object * Creates a new Runnable object
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment