我正在设计一个接受传入连接的服务器,客户端偶尔会发送服务器需要响应的请求,但大多数情况下服务器会检测到一些事件并将事件广播给所有连接的客户端。基本上我所拥有的是:
#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();
}
这里的问题是,每当设置 hEvent 时,只有 MyService 的第一个实例会调用它的 handle_signal。看起来一个事件只允许一个处理程序,一个处理程序可以处理多个事件。如何让多个处理程序处理一个事件?
如果我使事件手动重置事件,那么只要设置了事件,所有处理程序都会调用它们的 handle_signal。但这真的不是我想要的——我不希望客户多次收到同一事件的通知。
我通过使用信号量而不是事件来实现我的目标:
HANDLE const hEvent = ::CreateSemaphore(NULL, 0, 16, NULL);
并使 MyService 的构造函数和析构函数计算连接客户端的数量,以便我可以正确释放信号量的次数:
std::thread thr([=]()
{
while (true)
{
Sleep(1000);
ReleaseSemaphore(hEvent, clientCount, nullptr);
}
});
这似乎是错误的,闻起来很像黑客。ACE有没有正确的方法来做到这一点?