我正在通过以下方式使用 Berkeley 套接字选择功能。
/*Windows and linux typedefs/aliases/includes are made here with wsa
junk already taken care of.*/
/**Check if a socket can receive data without waiting.
\param socket The os level socket to check.
\param to The timeout value. A nullptr value will block forever, and zero
for each member of the value will cause it to return immediately.
\return True if recv can be called on the socket without blocking.*/
bool CanReceive(OSSocket& socket,
const timeval * to)
{
fd_set set = {};
FD_SET(socket, &set);
timeval* toCopy = nullptr;
if (to)
{
toCopy = new timeval;
*toCopy = *to;
}
int error = select((int)socket, &set, 0, 0, toCopy);
delete toCopy;
if (error == -1)
throw Err(); //will auto set from errno.
else if (error == 0)
return false;
else
return true;
}
我编写了一个类,它将监视一个套接字容器(包装在另一个类中)并将一个 ID 添加到一个单独的容器中,该容器存储有关哪些套接字准备好被访问的信息。地图是 unordered_map。
while(m_running)
{
for(auto& e : m_idMap)
{
auto id = e.first;
auto socket = e.second;
timeval timeout = ZeroTime; /*0sec, 0micro*/
if(CanReceive(socket,&timeout) &&
std::count(m_readyList.begin(),m_readyList.end(),socket) == 0)
{
/*only add sockets that are not on the list already.*/
m_readyList.push_back(id);
}
}
}
我相信很多人已经注意到,这段代码运行得非常快,并且像没有明天一样吞噬 CPU(40% 的 CPU 使用率,地图中只有一个套接字)。我的第一个解决方案是拥有一个智能等待功能,将每秒的迭代次数保持在一个设定值。这对某些人来说似乎很好。 我的问题是:如果不使用此方法,如何在套接字准备好时收到通知? 即使它可能需要一堆宏垃圾来保持便携,也没关系。我只能认为可能有某种方法可以让操作系统为我监视它并在套接字准备好时获得某种通知或事件。为了清楚起见,我选择不使用点网。
循环在自己的线程中运行,当套接字准备好时向软件的其他部分发送通知。整个事情是多线程的,它的每个部分(除了这部分)都使用一个基于事件的通知系统,消除了繁忙的等待问题。我知道这方面的事情变得依赖于操作系统并且受到限制。
编辑:套接字以阻塞模式运行(但选择没有超时,因此不会阻塞),但它们在专用线程中运行。编辑:该系统在其上的智能睡眠功能上表现出色,但不如在某些通知系统到位(可能来自操作系统)的情况下那么好。