feat(util): optimize SafeSignal for events from the main thread

This commit is contained in:
Aleksei Bavshin 2020-12-28 17:31:23 -08:00
parent 8a0e76c8d8
commit 79883dbce4
No known key found for this signature in database
GPG Key ID: 4F071603387A382A

View File

@ -6,6 +6,7 @@
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <queue> #include <queue>
#include <thread>
#include <tuple> #include <tuple>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -23,12 +24,23 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
template <typename... EmitArgs> template <typename... EmitArgs>
void emit(EmitArgs&&... args) { void emit(EmitArgs&&... args) {
if (main_tid_ == std::this_thread::get_id()) {
/*
* Bypass the queue if the method is called the main thread.
* Ensures that events emitted from the main thread are processed synchronously and saves a
* few CPU cycles on locking/queuing.
* As a downside, this makes main thread events prioritized over the other threads and
* disrupts chronological order.
*/
signal_t::emit(std::forward<EmitArgs>(args)...);
} else {
{ {
std::unique_lock lock(mutex_); std::unique_lock lock(mutex_);
queue_.emplace(std::forward<EmitArgs>(args)...); queue_.emplace(std::forward<EmitArgs>(args)...);
} }
dp_.emit(); dp_.emit();
} }
}
template <typename... EmitArgs> template <typename... EmitArgs>
inline void operator()(EmitArgs&&... args) { inline void operator()(EmitArgs&&... args) {
@ -55,6 +67,7 @@ struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
Glib::Dispatcher dp_; Glib::Dispatcher dp_;
std::mutex mutex_; std::mutex mutex_;
std::queue<arg_tuple_t> queue_; std::queue<arg_tuple_t> queue_;
const std::thread::id main_tid_ = std::this_thread::get_id();
// cache functor for signal emission to avoid recreating it on each event // cache functor for signal emission to avoid recreating it on each event
const slot_t cached_fn_ = make_slot(); const slot_t cached_fn_ = make_slot();
}; };