В моей программе существует один поток (получающий поток), который ответственен за получение запросов от сокета TCP и существует много потоков (рабочие потоки), которые ответственны за обработку полученных запросов. После того как запрос обрабатывается, я должен отправить ответ по TCP.
И вот вопрос. Я хотел бы отправить данные TCP в том же потоке, который я использую для получения данных. Этот поток после получения данных обычно ожидает новых данных в select()
. Таким образом, после того как рабочий поток закончил обрабатывать запрос и поместил ответ в очередь вывода, это должно сигнализировать о потоке получения, что существуют данные для отправки. Проблема состоит в том, что я не знаю, как отменить ожидание в select()
для выхода из ожидания и звонить send()
.
Или я буду использовать другой поток только для отправки данных по TCP?
Обновленный
MSalters, Artyom спасибо за Вас отвечает!
MSalters, прочитав Ваш ответ я нашел этот сайт: методы Winsock 2 ввода-вывода и чтение о WSAWaitForMultipleEvents()
. Моя программа на самом деле должна работать и над HP-UX и над Windows I, наконец решил использовать подход, который был предложен Artyom.
Вам нужно использовать что-то похожее на трюк с безопасным каналом, но в вашем случае вам нужно использовать пару подключенных сокетов TCP.
Как создать пару сокетов под 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);
}
Конечно, следует добавить некоторые проверки для возвращаемых значений.
select
не является родным API для Windows. Родным способом является WSAWaitForMultipleEvents. Если вы используете его для создания оповещаемого ожидания, вы можете использовать QueueUserAPC для указания ожидающему потоку отправить данные. (Это также может означать, что вам не нужно реализовывать собственную очередь вывода)
Типичная модель заключается в том, что рабочий обрабатывает свою собственную запись. Есть ли причина, по которой вы хотите отправлять все выходные данные через select
ing поток?
Если вы уверены в этой модели, вы можете заставить своих рабочих отправлять данные обратно в главный поток, используя дескрипторы файлов (pipe(2)
) и просто добавить эти дескрипторы в ваш select()
вызов.
И, если вы особенно уверены, что не собираетесь использовать трубы для отправки данных обратно в главный процесс, вызов select
позволяет указать таймаут. Вы можете выполнять busy-wait, проверяя рабочие потоки, и периодически вызывать select
, чтобы определить, с каких TCP-сокетов читать.
Еще одно быстрое и грязное решение - добавить сокеты localhost в набор. Теперь используйте эти сокеты в качестве очередей межпоточного взаимодействия. Каждый рабочий поток просто отправляет что-то в свой сокет, который попадает в соответствующий сокет в принимающем потоке. Это пробуждает select ()
, и ваш принимающий поток может затем повторить сообщение на соответствующем исходящем сокете.