イベントハンドラを登録したスレッドでデリゲートしてねっていうクラス
せっかく下にお勧めしたので、ネタ的に作成してみた。
ヘッダーにwindows.hを記述したくなかったのと
テンプレート名のSignatureに依存したくなかったので
TypeErasureするためにbindしまくってみた。invoke_helperはpimplっぽく?してみたつもりで
呼び出しの引数は参照つけてるけど・・その辺はどうしたらいいのか謎。->追記へ
あとは、ネーミングセンス爆発しろみたいになった。ちょっと読みにくいけど許してください。
//synchronized_event_delegator.h #pragma once #include <utility> #include <vector> #include <boost/function.hpp> #include <boost/bind.hpp> namespace umyu { struct invoke_helper { typedef boost::function<void ()> callback_handler_type; static void* get_thread_id(); static void invoke(void* thread_id,callback_handler_type* handler); }; template <typename Signature> struct synchronized_event_delegator { typedef Signature delegate_function_type; typedef boost::function<delegate_function_type> delegate_handler_type; synchronized_event_delegator& operator+=(const synchronized_event_delegator& delegator) { std::copy(delegator.handlers_.begin() ,delegator.handlers_.end(),std::back_inserter(handlers_)); return *this; } synchronized_event_delegator& operator+=(const delegate_handler_type& handler) { handlers_.push_back(std::make_pair(invoke_helper::get_thread_id(),handler)); return *this; } template <typename Sig> synchronized_event_delegator& operator+=(const boost::function<Sig>& handler) { handlers_.push_back(std::make_pair(invoke_helper::get_thread_id(),handler)); return *this; } void operator()() const { std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr=handlers_.begin(); std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr_end=handlers_.end(); for(itr;itr!=itr_end;++itr) invoke_helper::invoke(itr->first ,new invoke_helper::callback_handler_type(itr->second)); } template <typename Sender> void operator()(Sender& sender) const { std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr=handlers_.begin(); std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr_end=handlers_.end(); for(itr;itr!=itr_end;++itr) invoke_helper::invoke(itr->first ,new invoke_helper::callback_handler_type( boost::bind(itr->second,boost::ref(sender)))); } template <typename Sender,typename Arg1> void operator()(Sender& sender,Arg1& arg1) const { std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr=handlers_.begin(); std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr_end=handlers_.end(); for(itr;itr!=itr_end;++itr) invoke_helper::invoke(itr->first ,new invoke_helper::callback_handler_type( boost::bind(itr->second,boost::ref(sender),boost::ref(arg1)))); } void reset() { handlers_.clear(); } std::vector<std::pair<void*,delegate_handler_type> > handlers_; }; }
//synchronized_event_delegator.cpp #include "synchronized_event_delegator.h" #define _WIN32_WINNT 0x0501 #include <windows.h> namespace umyu { VOID APIENTRY invoke_helper_static_handler(ULONG_PTR handler) { invoke_helper::callback_handler_type* invoke_handler=(invoke_helper::callback_handler_type*)handler; (*invoke_handler)(); delete invoke_handler; } void* invoke_helper::get_thread_id() { HANDLE regist_thread; DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),GetCurrentProcess() ,®ist_thread,0,FALSE,DUPLICATE_SAME_ACCESS); return (void*)regist_thread; } void invoke_helper::invoke(void* thread_id,callback_handler_type* handler) { QueueUserAPC(&invoke_helper_static_handler,(HANDLE)thread_id,(ULONG_PTR)handler); } }
メインスレッドはSleepEx(0,TRUE)でプーリングを忘れずに。
追記
上記だと、呼び出し方によってスライシングしたり値でコピーされたりしますね。
以下のように参照もboost::refもはずして、呼び出す側でboost:refするように変更しました。
template <typename Sender,typename Arg1> void operator()(Sender sender,Arg1 arg1) const { std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr=handlers_.begin(); std::vector<std::pair<void*,delegate_handler_type> >::const_iterator itr_end=handlers_.end(); for(itr;itr!=itr_end;++itr) invoke_helper::invoke(itr->first ,new invoke_helper::callback_handler_type( boost::bind(itr->second,sender,arg1))); } ... synchronized_event_delegator<void (file&,unsigned long)> on_close; ... on_close(boost::ref(*this),error_code);