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()
INCLUDE_DIRECTORIES(${CampvisGlobalIncludeDirs})
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
################################################################################
......
......@@ -26,6 +26,7 @@ namespace sigslot {
}
void signal_manager::run() {
_this_thread_id = std::this_thread::get_id();
std::unique_lock<tbb::mutex> lock(_ecMutex);
while (! _stopExecution) {
......@@ -47,6 +48,10 @@ namespace sigslot {
tgt::Runnable::stop();
}
bool signal_manager::isCurrentThreadSignalManagerThread() const {
return std::this_thread::get_id() == _this_thread_id;
}
const std::string signal_manager::loggerCat_;
......
......@@ -90,6 +90,29 @@
#ifndef 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 <list>
......@@ -110,15 +133,30 @@
namespace sigslot {
/// Base class for signal handles that provides an interface to emit the signal.
class _signal_handle_base {
public:
/// Virtual destructor
virtual ~_signal_handle_base() {};
/// Emits the signal of this signal handle.
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>;
public:
......@@ -138,6 +176,12 @@ namespace sigslot {
*/
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
virtual void run();
/// \see Runnable:stop
......@@ -149,6 +193,7 @@ namespace sigslot {
/// Private destructor only for singleton
~signal_manager();
/// Typedef for the signal queue
typedef tbb::concurrent_queue<_signal_handle_base*> SignalQueue;
SignalQueue _signalQueue; ///< Queue for signals to be dispatched
......@@ -156,6 +201,8 @@ namespace sigslot {
std::condition_variable _evaluationCondition; ///< conditional wait to be used when there are currently no jobs to process
tbb::mutex _ecMutex; ///< Mutex for protecting _evaluationCondition
std::thread::id _this_thread_id;
static const std::string loggerCat_;
};
......@@ -1303,17 +1350,25 @@ namespace sigslot {
pclass->signal_connect(this);
}
void emitSignal()
void trigger()
{
signal_handle0* sh = new signal_handle0(this);
signal_manager::getRef().triggerSignal(sh);
}
void operator()()
void queue()
{
signal_handle0* sh = new signal_handle0(this);
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>
......@@ -1366,17 +1421,25 @@ namespace sigslot {
pclass->signal_connect(this);
}
void emitSignal(arg1_type a1)
void trigger(arg1_type a1)
{
signal_handle1* sh = new signal_handle1(this, a1);
signal_manager::getRef().triggerSignal(sh);
}
void operator()(arg1_type a1)
void queue(arg1_type a1)
{
signal_handle1* sh = new signal_handle1(this, a1);
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>
......@@ -1432,17 +1495,25 @@ namespace sigslot {
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_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_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>
......@@ -1500,17 +1571,25 @@ namespace sigslot {
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_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_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>
......@@ -1570,17 +1649,25 @@ namespace sigslot {
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_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_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>
......@@ -1642,17 +1729,25 @@ namespace sigslot {
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_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_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
......
......@@ -29,7 +29,6 @@
#include <ext/threading.h>
#include <tbb/atomic.h>
#include "core/coreapi.h"
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
* 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:
/**
* 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