Как отменить ожидание в выборе () в Windows

В моей программе существует один поток (получающий поток), который ответственен за получение запросов от сокета TCP и существует много потоков (рабочие потоки), которые ответственны за обработку полученных запросов. После того как запрос обрабатывается, я должен отправить ответ по TCP.

И вот вопрос. Я хотел бы отправить данные TCP в том же потоке, который я использую для получения данных. Этот поток после получения данных обычно ожидает новых данных в select(). Таким образом, после того как рабочий поток закончил обрабатывать запрос и поместил ответ в очередь вывода, это должно сигнализировать о потоке получения, что существуют данные для отправки. Проблема состоит в том, что я не знаю, как отменить ожидание в select() для выхода из ожидания и звонить send() .

Или я буду использовать другой поток только для отправки данных по TCP?

Обновленный

MSalters, Artyom спасибо за Вас отвечает!

MSalters, прочитав Ваш ответ я нашел этот сайт: методы Winsock 2 ввода-вывода и чтение о WSAWaitForMultipleEvents(). Моя программа на самом деле должна работать и над HP-UX и над Windows I, наконец решил использовать подход, который был предложен Artyom.

7
задан Sergei Kurenkov 29 July 2010 в 12:54
поделиться

4 ответа

Вам нужно использовать что-то похожее на трюк с безопасным каналом, но в вашем случае вам нужно использовать пару подключенных сокетов TCP.

  1. Создайте пару сокетов.
  2. Добавьте один в список select и также дождитесь его.
  3. Уведомить, записав в другой сокет из других потоков.
  4. Select немедленно активируется, так как один из сокетов доступен для чтения, считывает все данные в этом специальном сокете и проверьте все данные в очередях на отправку / получение

Как создать пару сокетов под Windows?

inline void pair(SOCKET fds[2])
{
    struct sockaddr_in inaddr;
    struct sockaddr addr;
    SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
    memset(&inaddr, 0, sizeof(inaddr));
    memset(&addr, 0, sizeof(addr));
    inaddr.sin_family = AF_INET;
    inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    inaddr.sin_port = 0;
    int yes=1;
    setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
    bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr));
    listen(lst,1);
    int len=sizeof(inaddr);
    getsockname(lst, &addr,&len);
    fds[0]=::socket(AF_INET, SOCK_STREAM,0);
    connect(fds[0],&addr,len);
    fds[1]=accept(lst,0,0);
    closesocket(lst);
}

Конечно, следует добавить некоторые проверки для возвращаемых значений.

16
ответ дан 6 December 2019 в 06:35
поделиться

select не является родным API для Windows. Родным способом является WSAWaitForMultipleEvents. Если вы используете его для создания оповещаемого ожидания, вы можете использовать QueueUserAPC для указания ожидающему потоку отправить данные. (Это также может означать, что вам не нужно реализовывать собственную очередь вывода)

7
ответ дан 6 December 2019 в 06:35
поделиться

Типичная модель заключается в том, что рабочий обрабатывает свою собственную запись. Есть ли причина, по которой вы хотите отправлять все выходные данные через selecting поток?

Если вы уверены в этой модели, вы можете заставить своих рабочих отправлять данные обратно в главный поток, используя дескрипторы файлов (pipe(2)) и просто добавить эти дескрипторы в ваш select() вызов.

И, если вы особенно уверены, что не собираетесь использовать трубы для отправки данных обратно в главный процесс, вызов select позволяет указать таймаут. Вы можете выполнять busy-wait, проверяя рабочие потоки, и периодически вызывать select, чтобы определить, с каких TCP-сокетов читать.

0
ответ дан 6 December 2019 в 06:35
поделиться

Еще одно быстрое и грязное решение - добавить сокеты localhost в набор. Теперь используйте эти сокеты в качестве очередей межпоточного взаимодействия. Каждый рабочий поток просто отправляет что-то в свой сокет, который попадает в соответствующий сокет в принимающем потоке. Это пробуждает select () , и ваш принимающий поток может затем повторить сообщение на соответствующем исходящем сокете.

0
ответ дан 6 December 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: