SetThreadAffinityMask пулированной нити - PullRequest
1 голос
/ 24 ноября 2010

Мне интересно, можно ли установить привязку процессора к потоку, полученному из пула потоков.Более конкретно, поток получается с помощью API-интерфейса TimerQueue, который я использую для реализации периодических задач.

Как примечание: я обнаружил, что TimerQueues - самый простой способ реализации периодических задач, но, поскольку это обычно долговременные задачи, может быть более целесообразно использовать для этой цели выделенные потоки?Кроме того, ожидается, что примитивы синхронизации, такие как семафоры и мьютексы, должны использоваться для синхронизации различных периодических задач.Подходят ли объединенные потоки для этих целей?

Спасибо!

РЕДАКТИРОВАТЬ1: Как отметил Лео, вышеупомянутый вопрос на самом деле является двумя слабо связанными.Первый связан со сродством процессоров объединенных потоков.Второй вопрос связан с тем, ведут ли потоки в пуле, полученные из API TimerQueue, точно так же, как потоки, созданные вручную, когда дело доходит до объектов синхронизации.Я перенесу этот второй вопрос в отдельную тему.

Ответы [ 2 ]

2 голосов
/ 24 ноября 2010

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

Вы уверены, что вам действительно нужно это сделать, хотя? Это очень, очень редконужно установить сродство процессора.(Я не думаю, что мне когда-либо нужно было делать это во всем, что я написал.)

Сходство потоков может означать две совершенно разные вещи. (Благодаря комментарию bk1e к моемуоригинальный ответ для указания на это. Я сам не осознал.)

  1. Что я бы назвал привязка к процессору : где поток должен последовательно выполняться натот же процессор.Это то, с чем имеет дело SetThreadAffinityMask, и код редко заботится об этом.(Обычно это происходит из-за проблем очень низкого уровня, таких как кэширование ЦП в высокопроизводительном коде. Обычно ОС делает все возможное, чтобы поддерживать потоки на одном и том же ЦП, и, как правило, вынуждает это делать иначе.)

  2. То, что я бы назвал привязка к потоку : где объекты используют локальное хранилище потока (или какое-либо другое состояние, связанное с потоком, к которому они обращаются) и будут работать неправильно, если последовательность действийне делается в одной и той же теме.

По вашему вопросу звучит так, как будто вы путаете # 1 с # 2. Сам поток не изменится пока ваш обратный вызов работает .Во время работы потока он может перепрыгивать между процессорами, но это нормально, и вам не о чем беспокоиться (кроме очень особых случаев).

Мьютексы, семафоры и т. Д. Не волнует, если поток переходит междуПроцессоры.

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

Некоторые объекты синхронизации будут заботиться о том, выполняется ли ваш код обратного вызова в одном потоке, а затем, думая, что он удерживает блокировки этих объектов, запускается сновав другой теме.(Первый поток все еще будет удерживать блокировки, а не второй, хотя это зависит от того, какой тип объекта синхронизации вы используете. Некоторым все равно.) Однако это не № 1;это # ​​2, а не то, с чем вы будете иметь дело с SetThreadAffinityMask.

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

С другой стороны, Event (CreateEvent) не заботится о том, какие потоки создаются,сигнализировать или уничтожить это.Вы можете сигнализировать о событии в одном потоке, а затем сбросить его в другом, и это нормально (на самом деле нормально).

Редко также можно было бы удерживать объект синхронизации между двумя отдельными запусками вашего обратного вызова (чтобудет вызывать взаимоблокировки, хотя, безусловно, существуют ситуации, когда вы могли бы на законных основаниях хотеть / делать такие вещи).Однако, если вы создали (например) COM-объект с многопоточностью, то к нему вы бы хотели получить доступ только из одного конкретного потока.

0 голосов
/ 24 ноября 2010

Ты не должен.Вы должны использовать этот поток только для текущей работы, на процессоре, в котором он запущен в тот момент.Помимо очевидной неэффективности, пул потоков может уничтожить каждый поток, как только вы закончите, и создать новый для вашей следующей работы.Маски сродства не исчезнут так скоро на практике, но еще сложнее их отладить, если они исчезнут наугад.

...