CAsyncSocket и многопоточность - PullRequest
0 голосов
/ 06 апреля 2009

Я использую MFC CAsyncSocket для сетевого взаимодействия в многопоточной среде. После нескольких часов попыток заставить принятые сокеты принимать входящие данные я наткнулся на страницу, на которой говорится, что для вызова функции OnReceive в CAsyncSocket сокет должен находиться в контексте основного потока графического интерфейса. Перемещение его в основной поток графического интерфейса позволило сокету начать получать данные.

Мой вопрос такой: кто-нибудь знает обходной путь для этого? Сокет ранее находился в потоке графического интерфейса, и OnAccept вызывался нормально. Принятый сокет может быть использован для отправки данных без проблем, просто не может ничего получить. Я бы предпочел не перепроектировать эту часть программного обеспечения, если я могу избежать этого.

1 Ответ

3 голосов
/ 06 апреля 2009

Было бы проще просто создать отдельный поток с собственной очередью сообщений для ваших сокетов? Я не думаю, что CAsyncSocket нужно создавать в основной очереди сообщений, просто в какой-то очереди сообщений. См. Документацию по CWinThread, чтобы узнать, как создать отдельный поток с собственной MFC-совместимой очередью сообщений.

К сожалению, крайне важно, чтобы вы вызывали все операции с сокетами из контекста нового потока. MFC использует глобальное состояние в скрытых классах, которые используют локальное хранилище потоков для хранения информации о потоках, и эта информация используется во многих методах CAsynchSocket. Это означает, что CAsynchSocket имеет привязку к потоку, и вы всегда должны использовать и создавать его в любом потоке, который будет его обработчиком сообщений.

Один из подходов заключается в создании CWinThread, создании собственного настраиваемого скрытого окна MFC в этом потоке (путем создания окна в контексте этого потока) и создания сообщений и обработчиков сообщений в этом окне для всех операций сокета. (создание, подключение и т. д.) вы делаете. Убедитесь, что поток перекачивает сообщения (для этого используется метод «Run ()»), а затем отправьте / отправьте сообщения в ваше окно для управления сокетами.

Также помните, что обратные вызовы из вашего сокета будут входить в отдельный поток, а не в пользовательский интерфейс или рабочие потоки. Вам нужно беспокоиться о состоянии гонки и, возможно, о проблемах схожести потоков GUI, если вы обновляете объекты GUI.

Если вас беспокоит влияние проекта, просто создайте свой собственный прокси-объект CThreadSafeAsynchSocket и делегируйте его реальной реализации через передачу сообщений в скрытое окно. Вы можете использовать SendMessage для блокировки операций и PostMessage для асинхронных операций. Если вы поместите конструктор в фабричный объект, вы можете отложить создание потока сокета до тех пор, пока он не понадобится.

Последнее, о чем я могу подумать, это то, что вам нужно будет определить, когда все ваши прокси исчезли, и закрыть поток. Вы можете использовать глобальный счетчик ссылок, управляемый конструкторами / деструкторами CThreadSafeAsynchSocket, чтобы определить, когда закрывать поток. Если вы не закроете поток, ваше приложение будет зависать со скрытым окном даже после закрытия основного окна приложения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...