Когда использовать QueueUserAPC()?

Я понимаю, что такое APC, как он работает и как его использует Windows, но я не понимаю, когда я (как программист) должен использовать QueueUserAPC вместо, скажем, потока волокна или потока потока.

Когда следует выбрать QueueUserAPC и почему?

Ответы

Ответ 1

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

Скажем, у вас есть основной поток и рабочий поток. Рабочий поток открывает сокет на файловый сервер и начинает загрузку файла 10 ГБ, вызывая recv() в цикле. Основной поток хочет, чтобы рабочий поток делал что-то еще в своем простое, пока он ждет сетевых пакетов; он может поставить в очередь функцию, которая будет выполняться на рабочем столе, в противном случае она будет ждать и ничего не делать.

Вы должны быть осторожны с APC, потому что, как и в упомянутом выше сценарии, вы не захотите сделать другой блокирующий вызов WinSock (что приведет к поведению undefined). Вы действительно должны смотреть, чтобы найти хорошее применение этой функции, потому что вы можете сделать то же самое другими способами. Например, если другой поток проверяет событие каждый раз, когда он собирается заснуть, вместо того, чтобы давать ему функцию для запуска во время ожидания. Очевидно, что APC будет проще в этом сценарии.

Это похоже на то, что у вас есть сотрудник службы звонков, который сидит и ждет телефонных звонков, и вы даете этому человеку небольшие задачи во время простоя. "Вот, решите этот кубик Рубика, пока вы ждете". Хотя, когда поступает телефонный звонок, человек не будет класть кубик Рубика, чтобы ответить на звонок (APC должен вернуться, прежде чем поток сможет вернуться к ожиданию).

QueueUserAPC также полезен, если есть один поток (Thread A), который отвечает за некоторую структуру данных, и вы хотите выполнить некоторую операцию над структурой данных из другого потока (Thread B), но вы не Не хотите иметь накладные расходы/сложность синхронизации, пытаясь поделиться этими данными между двумя потоками. Если очередь Thread B находится в очереди на Thread A, которая только поддерживает эту структуру, вы выполняете любую произвольную функцию, которую вы хотите использовать для этих данных, не беспокоясь о синхронизации.

Это просто еще один инструмент, подобный пулу потоков. Однако с пулом потоков вы не можете отправить задачу в конкретный поток. Вы не контролируете, где работа выполнена. Когда вы ставите в очередь задачу, которая может привести к созданию целого нового потока. Вы можете поставить в очередь две задачи, и они выполняются одновременно на двух разных потоках. С помощью QueueUserAPC вы можете быть уверены, что задачи будут выполняться по порядку и по указанному вами потоку.