Связь между потоками. Как отправить сигнал в другой поток

в моем приложении у меня есть два потока

  1. "основной поток", который занят большую часть времени
  2. "дополнительный поток", который отправляет некоторый HTTP-запрос и который блокирует, пока не получит ответ.

однако HTTP-ответ может обрабатываться только основным потоком, так как он полагается на его локальное хранилище потоков и на не-threadsafe функции.

Я ищу способ сообщить основной поток, когда HTTP-ответ был получены и соответствующие данные. Основной поток должен быть прерван дополнительным потоком и обработать HTTP-ответ как можно скорее, а затем продолжить работу с точки, где он был прерван раньше.

  • один из способов, о котором я могу думать, заключается в том, что дополнительный поток приостанавливает основной поток с помощью SuspendThread, копирует TLS из основного потока с помощью некоторого встроенного ассемблера, выполняет саму функцию обработки ответов и возобновляет основную нить потом.

  • другим способом в моих мыслях является установка точки останова на некоторый конкретный адрес во второй подпрограмме обратного вызова потоков, так что основной поток получает уведомление, когда второй указатель инструкции потоков делает шаги на этой точке останова - и, следовательно, - получил ответ HTTP.

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

что я могу использовать прервать мой основной поток, говоря, что он должен быть вежливым и обрабатывать HTTP-ответ, прежде чем делать что-либо еще? Ответы без зависимостей от библиотек приветствуются, но я бы также взял некоторую зависимость, если она предоставляет какое-то хорошее решение.

после вопрос (относительно решения QueueUserAPC) был дан ответ и объяснено, что нет безопасного метода, чтобы иметь пуш-поведение в моем случае.

7 ответов


Это может быть один из тех случаев, когда человек работает над очень конкретной идеей, не переосмысливая общую картину. Не существует особого механизма, с помощью которого один поток может прекратить выполнение в текущем контексте, перейти к чему-то другому и возобновить выполнение на той же самой линии, от которой он оторвался. Если бы это было возможно, это в первую очередь разрушило бы цель иметь нити. Как вы уже упоминали, не отступая назад и не пересматривая общий архитектура, самый элегантный из ваших вариантов, похоже, использует другой поток, чтобы дождаться ответа HTTP, приостановить основной поток в безопасном месте, обработать ответ самостоятельно, а затем возобновить основной поток. В этом случае вы можете переосмыслить, имеет ли смысл локальное хранилище потоков или что-то немного более высокое по области будет более подходящим, так как вы потенциально можете потратить много циклов, копируя его каждый раз, когда вы прерываете основной поток.


то, что вы описываете то, что QueueUserAPC делает. Но идея использовать его для такого рода синхронизации делает меня немного неудобным. Если вы не знаете, что основной поток находится в безопасное место, чтобы прервать его, то вы, вероятно, не должны прерывать его.

Я подозреваю, что вам было бы лучше дать работу основного потока другому потоку, чтобы он мог сидеть и ждать, пока вы отправите ему уведомления для обработки работы, которую только он может ручка.

PostMessage или PostThreadMessage обычно работает очень хорошо для передачи битов работы в основной поток. Отправленные сообщения обрабатываются до ввода сообщений пользователем, но не до тех пор, пока поток не будет готов к ним.


Я могу не понять вопрос, но CreateSemaphore и WaitForSingleObject должны работать. Если один поток ждет семафора, он возобновится, когда другой поток подаст сигнал.

обновление на основе комментария: основной поток может вызывать WaitForSingleObject с нулевым временем ожидания. В этой ситуации он возобновится немедленно, если семафор не будет сигнализирован. Затем основной поток может проверять его на периодической основе.


похоже, что ответ должен быть обнаружен из Microsoft MSDN. Особенно в разделе на 'синхронизация выполнения нескольких потоков'


Если ваш основной поток-поток GUI, почему бы не отправить ему сообщение Windows? Это то, что мы все делаем для взаимодействия с win32 GUI из рабочих потоков.


один из способов сделать это-периодически проверять, получен ли HTTP-ответ.

вам лучше сказать, чего вы пытаетесь достичь.


в этой ситуации я бы сделал пару вещей. Прежде всего, я бы перестроил работу, которую делает основная нить, чтобы разбиться на как можно более мелкие кусочки. Это дает вам ряд безопасных мест, чтобы прервать исполнение. Затем вы хотите создать рабочую очередь, возможно, используя Microsoft slist. Слист даст вам возможность иметь один поток, добавляющий в то время как другой читает без необходимости блокировки.

Как только вы это сделаете, вы можете по сути, сделайте свой основной поток циклом над каждой частью работы, периодически проверяя, есть ли запросы для обработки в очереди. Что приятно в такой архитектуре, так это то, что вы можете довольно легко устранить локализованное хранилище потоков и распараллелить основной поток, преобразовав slist в рабочую очередь (возможно, все еще используя slist) и сделав небольшие фрагменты работы и ответы в рабочие объекты, которые могут быть динамически распределены по всему потоку любые доступные темы.