I need to have some thread-safe event handler (like C#'s EventHandler
), so I made one. Here is my event handler class and sample code (compiled with VS2013). Is this code OK to be operated in multithreaded environment?
#include <functional>
#include <memory>
#include <atomic>
#include <list>
#include <conio.h>
////////////////////////////////////////////////////////////////////////////
// Event Handler class
template <typename _EventArg>
class EventHandler
{
public:
EventHandler()
{
m_flag.clear();
}
EventHandler(const EventHandler& other)
{
m_flag.clear();
m_ptr = other.m_ptr;
}
EventHandler& operator= (const EventHandler& other)
{
m_flag.clear();
m_ptr = other.m_ptr;
return *this;
}
virtual ~EventHandler()
{
while (m_flag.test_and_set(std::memory_order_acquire));
}
template <typename _Type>
EventHandler(void (_Type::*memFn)(_EventArg), _Type *obj)
{
m_flag.clear();
m_ptr.reset(new std::function<void(_EventArg)>(std::bind(memFn, obj, std::placeholders::_1)));
}
void operator() (_EventArg e)
{
while (m_flag.test_and_set(std::memory_order_acquire));
if (m_ptr.get()) { (*m_ptr)(e); }
m_flag.clear(std::memory_order_release);
}
bool operator== (const EventHandler& other)
{
while (m_flag.test_and_set(std::memory_order_acquire));
bool equal = (m_ptr == other.m_ptr);
m_flag.clear(std::memory_order_release);
return equal;
}
private:
std::atomic_flag m_flag;
std::shared_ptr<std::function<void(_EventArg)>> m_ptr;
};
template <typename _Type>
class IEvent
{
public:
IEvent()
{
m_flag.clear();
}
virtual ~IEvent()
{
while (m_flag.test_and_set(std::memory_order_acquire));
}
void operator+= (const EventHandler<_Type>& handler)
{
while (m_flag.test_and_set(std::memory_order_acquire));
m_list.push_back(handler);
m_flag.clear(std::memory_order_release);
}
void operator-= (const EventHandler<_Type>& handler)
{
while (m_flag.test_and_set(std::memory_order_acquire));
m_list.remove(handler);
m_flag.clear(std::memory_order_release);
}
void operator() (_Type arg)
{
while (m_flag.test_and_set(std::memory_order_acquire));
for (auto& f : m_list) { f(arg); }
m_flag.clear(std::memory_order_release);
}
private:
std::atomic_flag m_flag;
std::list<EventHandler<_Type>> m_list;
// make non-copyable
IEvent(const IEvent&);
IEvent& operator= (const IEvent&);
};
////////////////////////////////////////////////////////////////////////////
// Event source class
class CSource {
public:
void RaiseEvent(int value)
{
MyEvent(value); // Raise event
}
IEvent<int> MyEvent;
};
// Event receiver class
class CReceiver {
public:
void MyHandler1(int e)
{
printf("CReceiver::MyHandler1 called with value %d\n", e);
}
void MyHandler2(int e)
{
printf("CReceiver::MyHandler2 called with value %d\n", e);
}
};
void main()
{
CSource source;
CReceiver receiver;
// define event handler
EventHandler<int> handler1 = EventHandler<int>(&CReceiver::MyHandler1, &receiver);
EventHandler<int> handler2 = EventHandler<int>(&CReceiver::MyHandler2, &receiver);
// add event handler
source.MyEvent += handler1;
source.MyEvent += handler2;
// raise event with value 1234!
source.RaiseEvent(1234);
// remove event handler
source.MyEvent -= handler1;
source.MyEvent -= handler2;
_getch();
}