I am designing a server that accepts incoming connections, the clients occasionally send requests which the server needs to respond, but mostly the server detects some events and broadcasts the event to all the connected clients. Basically what I have is this:
#include <ace/Acceptor.h>
#include <ace/INET_Addr.h>
#include <ace/Reactor.h>
#include <ace/SOCK_Acceptor.h>
#include <ace/SOCK_Stream.h>
#include <ace/Svc_Handler.h>
#include <iostream>
#include <thread>
// XXX: for simplicity
HANDLE const hEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
class MyService
: public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_NULL_SYNCH>
{
public:
MyService() : signalCount_(0) { }
int open(void*) override
{
ACE_Reactor::instance()->register_handler(
this,
ACE_Event_Handler::READ_MASK);
ACE_Reactor::instance()->register_handler(
this,
hEvent);
return 0;
}
int handle_input(ACE_HANDLE) override
{
// Handle stuff coming in from clients.
return 0;
}
int handle_signal(int, siginfo_t*, ucontext_t*) override
{
// handle the detected event, send to client.
std::cout
<< signalCount_++ << " "
<< this << " "
<< __FUNCTION__
<< std::endl;
return 0;
}
unsigned signalCount_;
};
typedef ACE_Acceptor<MyService, ACE_SOCK_ACCEPTOR> MyAcceptor;
int main()
{
WSADATA wsData;
WSAStartup(MAKEWORD(2, 0), &wsData);
std::thread thr([=]()
{
// simulate the events.
Sleep(1000);
SetEvent(hEvent);
});
auto r = ACE_Reactor::instance();
MyAcceptor acceptor(ACE_INET_Addr(1234), r);
r->run_reactor_event_loop();
}
The problem here is that whenever hEvent is set, only the first instance of MyService gets its handle_signal called. It looks like only one handler is allowed for one event, bit a handler can handle multiple events. How can I make multiple handlers handler a single event?
If I make the event manual-reset-event, then all the handlers get their handle_signal called as long as the event is set. But that is really not what I want - I don't want a client to be notified of the same event multiple times.
I kind of achieved my goal by using a semaphore instead of an event:
HANDLE const hEvent = ::CreateSemaphore(NULL, 0, 16, NULL);
And made construtor and destructor of MyService count the number of connected clients so that I could release the semaphore correct number of times:
std::thread thr([=]()
{
while (true)
{
Sleep(1000);
ReleaseSemaphore(hEvent, clientCount, nullptr);
}
});
This seems wrong and smells a lot like a hack. Is there a proper way of doing this with ACE?