简体   繁体   English

CAsyncSocket和线程

[英]CAsyncSocket and threading

I'm using a MFC CAsyncSocket to do some network communication in a multi-threaded environment. 我正在使用MFC CAsyncSocket在多线程环境中进行一些网络通信。 After several hours of trying to get the accepted sockets to accept incoming data I came across a page that states that for a CAsyncSocket's OnReceive function to be called the socket has to be in the context of the main GUI thread. 在尝试使接受的套接字接受输入的数据几个小时之后,我遇到了一个页面,该页面指出要调用CAsyncSocket的OnReceive函数,套接字必须在主GUI线程的上下文中。 Moving it to the main GUI thread has allowed the socket to start receiving data. 将其移动到主GUI线程已允许套接字开始接收数据。

My question is this: does anyone know of a workaround for this? 我的问题是:有人知道解决方法吗? The socket was on a GUI thread before and the OnAccept was being called fine. 之前,套接字在GUI线程上,并且OnAccept被称为罚款。 The accepted socket could be used to send data no problem, just couldn't receive anything. 接受的套接字可以用来发送数据,没问题,只是什么也收不到。 I'd rather not have to re-architect this part of the software if I can avoid it. 如果可以避免的话,我宁愿不必重新设计软件的这一部分。

Would it be simpler to simply create a separate thread with its own message queue for your sockets? 仅为套接字创建一个具有自己的消息队列的单独线程会更简单吗? I don't think CAsyncSocket needs to be created on the main message queue, just some message queue. 我认为不需要在主消息队列上创建CAsyncSocket,而只需在某些消息队列上创建CAsyncSocket。 See the documentation for CWinThread to see how to create a separate thread with its own MFC-compatible message queue. 请参阅CWinThread文档,以了解如何使用其自己的MFC兼容消息队列创建单独的线程。

Unfortunately, it is crucial that you call all socket operations from the context of the new thread. 不幸的是,至关重要的是您必须从新线程的上下文中调用所有套接字操作。 MFC uses global state in hidden classes that use thread-local storage to hold per-thread information, and that information is used in many of the CAsynchSocket's methods. MFC在隐藏类中使用全局状态,这些隐藏类使用线程本地存储来保存每个线程的信息,并且该信息在许多CAsynchSocket的方法中都使用。 That means CAsynchSocket has thread affinity and you must always use and create it in whatever thread is to be its message pump. 这意味着CAsynchSocket具有线程相似性,您必须始终在要用作其消息泵的任何线程中使用和创建它。

One approach would be to create a CWinThread, create your own custom MFC hidden window on that thread (by creating the window in the context of that thread), and create messages and message handlers on that window for all of the socket operations (creating, connecting, etc) you do. 一种方法是创建一个CWinThread,在该线程上创建自己的自定义MFC隐藏窗口(通过在该线程的上下文中创建窗口),并在该窗口上为所有套接字操作创建消息和消息处理程序(创建,连接等)。 Assure that the thread is pumping messages (the "Run()" method does this) and then post/send messages to your window to control your socket(s). 确保线程正在泵送消息(“ Run()”方法执行此操作),然后将消息发送/发送到窗口以控制您的套接字。

Also, remember that callbacks from your socket will come in on a separate thread than your UI or worker threads. 另外,请记住,来自套接字的回调将进入与UI或工作线程不同的线程。 You'll need to worry about race conditions and possibly GUI thread affinity issues if you're updating GUI objects. 如果要更新GUI对象,则需要担心争用条件以及可能的GUI线程关联性问题。

If you're worried about the design impact, just create your own CThreadSafeAsynchSocket proxy object and delegate to the real implementation through message-passing to your hidden window. 如果您担心设计的影响,只需创建自己的CThreadSafeAsynchSocket代理对象,然后通过将消息传递到隐藏窗口将其委托给实际实现即可。 You can use SendMessage for blocking operations and PostMessage for asynchronous operations. 您可以使用SendMessage进行阻止操作,并使用PostMessage进行异步操作。 If you wrap the constructor in a factory object, you can delay creation of the socket thread until its needed. 如果将构造函数包装在工厂对象中,则可以延迟套接字线程的创建,直到需要它为止。

The last concern I can think of is that you'll need to detect when all your proxies have gone away and shut down the thread. 我能想到的最后一个问题是,您需要检测所有代理何时消失并关闭线程。 You can use a global reference count managed by the CThreadSafeAsynchSocket's constructors/destructors to detect when to shut down the thread. 您可以使用CThreadSafeAsynchSocket的构造函数/析构函数管理的全局引用计数来检测何时关闭线程。 Failing to shut down the thread will keep your app hanging about with a hidden window even after you close your main app window. 即使关闭主应用程序窗口,未关闭线程也会使您的应用程序在隐藏的窗口中徘徊。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM