如何防止 WSASend() 阻塞我的 UI 线程?

How to prevent WSASend() from blocking my UI thread?

我想使用 Overlapped I/O 和 Completion Routine 来处理客户端连接。

在我的UI线程中我想使用WSASend(),但是为了让系统调用我的回调函数来通知我数据已经发送,UI线程必须处于等待状态,但这会冻结我的 UI!

我该如何解决这个问题?

我同意@DavidHeffernan - UI 线程应该做 UI 事情。 IO 线程肯定需要绑定和端口(服务器),或对等地址和端口(客户端)。来自 ConnectEx 或 AcceptEx 的套接字肯定更好地加载到 IO 线程中,但是带有(此时未定义)套接字成员的 Socket class 肯定可以在 UI 线程中创建并发出信号用于处理的 IO 线程。缓冲区是构成套接字的一部分 class,还是单独的缓冲区 class,是一个设计考虑因素。

一个实现,(我已经成功使用):

Design/define 一个 'Inter Thread Comms',(ITC'),消息 class。它有一个 'command' 枚举成员,可以告诉其他线程做一些事情,以及此类消息中可能需要的任何其他有用的东西

从 ITC 导出 'Socket' class。它具有 IP/port、套接字句柄和任何其他可能需要的字符串成员。

从 ITC 导出 'Buffer' class。它有一个 'BoundSocket' 成员,buffer-space 和一个 'OVERLAPPED' 结构。

与 IO 线程通信相当容易。由于它必须可变地等待某些东西,它可以等待管理 'Commands' ConcurrentQueue 的信号量。

如果您 UI 希望指示 IO 线程连接到服务器,它会创建一个 Socket 实例(新),从 UI 元素加载 IP 和端口成员,将 Command 枚举设置为 'Connect',将套接字推送到 Commands 队列并向信号量发出信号,(ReleaseSemaphore)。

IO 线程中的 alertable 等待然后 returns 和 WAIT_OBJECT_0,(它需要忽略 returns 和 WAIT_IO_COMPLETION)所以知道命令已经执行排队。它从命令队列中弹出它并根据命令枚举(可能打开它)执行所需的 action/s。对于连接,这将涉及重叠 'ConnectEx' 调用以排队连接请求并设置连接完成处理程序。

连接完成处理程序在调用时检查连接是否成功,如果是,则可以新建一个缓冲区,加载它,向服务器发出 WSARecv 以发送内容并将返回的 Socket 对象存储在一个容器。如果失败,它可以加载套接字 使用合适的错误消息并将其 PostMessage 返回到 UI 线程以通知用户失败。

看 - 这并不难,不需要 10000 行代码:)

我唯一不知道如何立即做的是从完成例程中返回的 OVERLAPPED 结构中获取套接字对象的 'this'。在 32 位系统上,我将 Buffer 'this' 推入 Buffer 实例中重叠结构的 hEvent 字段,并将其强制转换回完成例程。 Buffer 实例有一个 Socket 引用,所以工作完成了。在 64 位系统上,hEvent 没有足够的空间来存储 48/64 位 'this' 缓冲区指针,并且(显然),这需要一个扩展的 OVERLAPPED 结构:(不知道这是怎么做的 - 也许你会找出:)

[edit] @BenVoigt 对 32/64 位“在完成例程中获取套接字上下文 'this'”问题提出了建议 - 这比我想象的要容易:)