c - 将 CompletionRoutine 与多个套接字一起使用时如何同步 WSARecvFrom() 的处理

标签 c multithreading sockets winapi

来自 MSDN 文档:

The transport providers allow an application to invoke send and receive operations from within the context of the socket I/O completion routine, and guarantee that, for a given socket, I/O completion routines will not be nested. This permits time-sensitive data transmissions to occur entirely within a preemptive context.

在我们的系统中,我们确实有一个线程为多个套接字调用 WSARecvFrom()。该线程有一个 CompletionRoutine 来处理来自 WSARecvFrom() opverlapped I/O 的所有回调。

我们的测试表明,这个完成例程的调用方式类似于从中断触发。调用套接字,同时仍在处理来自其他套接字的完成例程。

我们如何防止该完成例程在仍在处理来自其他套接字的输入时未被调用?

我们可以使用什么数据处理序列化?

请注意,有数百个套接字接收和发送实时数据。等待多个对象的同步不适用,因为 Win32 API 定义了最多 64 个对象。

我们不能使用信号量,因为当新调用时,旧的正在进行的处理会被中断,因此信号量不会被释放,并且新的处理将永远阻塞。

关键部分或互斥体不是一个选项,因为完成例程回调是在同一线程内进行的,因此 CS 或互斥体无论如何都会接受,并且不会等到旧处理完成。

有人有一个想法或者更好的方法来序列化(同步)​​数据处理吗?

最佳答案

如果您阅读 WSARecvFrom() documentation再仔细一点,它还说:

The completion routine follows the same rules as stipulated for Windows file I/O completion routines. The completion routine will not be invoked until the thread is in an alertable wait state such as can occur when the function WSAWaitForMultipleEvents with the fAlertable parameter set to TRUE is invoked.

Alertable I/O documentation然后指出:

When the thread enters an alertable state, the following events occur:

  1. The kernel checks the thread's APC queue. If the queue contains callback function pointers, the kernel removes the pointer from the queue and sends it to the thread.
  2. The thread executes the callback function.
  3. Steps 1 and 2 are repeated for each pointer remaining in the queue.
  4. When the queue is empty, the thread returns from the function that placed it in an alertable state.

因此,给定线程实际上不可能将多个挂起的完成例程相互重叠,因为线程以序列化方式接收和处理例程。我能看到不同的唯一方法是,完成例程是否正在执行某些操作将线程置于第二个可警报状态,而先前的可警报状态仍然有效。我不确定 Windows 在这种情况下会做什么,但无论如何您都应该避免这样做。

Note there are hundrets of sockets receiving and sending realtime data. Synchronisation with waiting for multiple objects is not applicable as there is a maximum of 64 defined by the Win32 API

WaitForMultipleObjects() documentation告诉您如何解决该限制:

To wait on more than MAXIMUM_WAIT_OBJECTS handles, use one of the following methods:

• Create a thread to wait on MAXIMUM_WAIT_OBJECTS handles, then wait on that thread plus the other handles. Use this technique to break the handles into groups of MAXIMUM_WAIT_OBJECTS.

• Call RegisterWaitForSingleObject to wait on each handle. A wait thread from the thread pool waits on MAXIMUM_WAIT_OBJECTS registered objects and assigns a worker thread after the object is signaled or the time-out interval expires.

无论如何,我不会等待套接字,这不是很有效。只要它们做的是安全的事情,使用完成例程就可以。

否则,我建议您停止使用完成例程并改用 I/O Completion Port改为套接字 I/O。然后您可以更好地控制何时向您报告完成结果,因为您必须调用 GetQueuedCompletionStatus()自己获取每个 I/O 操作的结果。您可以拥有与单个 IOCP 关联的多个套接字,然后拥有一小部分线程(通常每个 CPU 核心一个线程效果最好),所有线程都在该 IOCP 上调用 GetQueuedCompletionStatus()。这样,您可以并行处理多个 I/O 结果,因为它们将位于不同的线程上下文中,并且在同一线程中不能相互重叠。然而,这确实意味着您可以在一个线程中执行 I/O 操作,而结果可能会显示在不同的线程中。只需确保您的完成处理是线程安全的。

关于c - 将 CompletionRoutine 与多个套接字一起使用时如何同步 WSARecvFrom() 的处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24203394/

相关文章:

c++ - 在 C++ 中使用多线程进行快速排序

c - 通过 SSL 套接字反向 shell

c - 将大型数组从 java 传递到 c 时出现 jni 错误

c - 如何将一个 TCP 服务器连接到另一个 TCP 服务器

c - C 指针数组中的负索引

multithreading - 电信软件硬多线程问题的设计模式

java - 数据库连接池中的每个连接是否都由一个线程支持?

c - c中信号处理函数的签名

node.js - ERR_CERT_INVALID : When trying to connect client using ngx-socket-io to nodejs socketio using HTTPS self-assigned certificate

python - 套接字错误 : [Errno 111] Connection refused