У меня есть рабочий поток, который прослушивает сокет TCP для входящего трафика и буферизирует полученные данные для доступа основного потока (назовем этот сокет A ). Однако рабочий поток также должен выполнять некоторые регулярные операции (скажем, раз в секунду), даже если данные не поступают. Поэтому я использую select()
с таймаутом, поэтому мне не нужно продолжать опрос , (Обратите внимание, что вызов receive()
в неблокирующем сокете и последующий спящий режим на секунду не годится: входящие данные должны быть немедленно доступны для основного потока, даже если основной поток не всегда может сразу его обработать отсюда и необходимость буферизации.)
Теперь мне также нужно иметь возможность сигнализировать рабочему потоку о немедленном выполнении каких-то других действий; из основного потока мне нужно, чтобы рабочий поток select()
сразу возвращался. Пока что я решил это следующим образом (подход, принятый в основном из здесь и здесь ):
При запуске программы рабочий поток создает для этой цели дополнительный сокет типа дейтаграммы (UDP) и привязывает его к некоторому случайному порту (назовем этот сокет B ). Аналогично, основной поток создает сокет дейтаграммы для отправки. При вызове select()
рабочий поток теперь перечисляет как A , так и B в fd_set
. Когда основной поток должен подать сигнал, он sendto()
передает пару байтов соответствующему порту на localhost
. Возвращаясь в рабочий поток, если B остается в fd_set
после возврата select()
, то вызывается recvfrom()
и полученные байты просто игнорируются.
Кажется, это работает очень хорошо, но я не могу сказать, что мне нравится решение, в основном потому, что оно требует привязки дополнительного порта для B , а также потому, что оно добавляет несколько дополнительных вызовов API сокетов, которые могут я думаю, что мне это не удастся - и мне не хочется выяснять, какое действие необходимо предпринять для каждого из случаев.
В идеале я хотел бы вызвать некоторую функцию, которая принимает A в качестве входных данных и ничего не делает, кроме того, что select()
возвращает сразу. Однако я не знаю такой функции. (Думаю, я мог бы, например, shutdown()
сокет, но побочные эффекты не совсем приемлемы:)
Если это невозможно, вторым лучшим вариантом будет создание B , который намного громче, чем настоящий сокет UDP, и на самом деле не требует выделения каких-либо ограниченных ресурсов (помимо разумного количества объем памяти). Я предполагаю, что доменные сокеты Unix сделали бы именно это, но: решение не должно быть намного менее кроссплатформенным, чем у меня в настоящее время, хотя некоторое умеренное количество #ifdef
вещей хорошо. (Я ориентируюсь в основном на Windows и Linux - и, кстати, пишу на C ++.)
Пожалуйста, не предлагайте рефакторинг, чтобы избавиться от двух отдельных потоков. Эта схема необходима, потому что основной поток может быть заблокирован на длительные периоды (например, при выполнении интенсивных вычислений - и я не могу периодически вызывать receive()
из самого внутреннего цикла вычислений), а тем временем кому-то нужно буферизовать входящие данные (и по причинам, которые я не могу контролировать, они не могут быть отправителями).
Теперь, когда я писал это, я понял, что кто-то определенно собирается ответить просто " Boost.Asio ", поэтому я только что впервые посмотрел на него ... Не смог найти очевидного решение, хотя. Обратите внимание, что я также не могу (легко) повлиять на то, как создается сокет A , но я должен иметь возможность позволить другим объектам оборачивать его, если это необходимо.