45817 (Эффективная многопоточность), страница 4

2016-07-31СтудИзба

Описание файла

Документ из архива "Эффективная многопоточность", который расположен в категории "". Всё это находится в предмете "информатика" из , которые можно найти в файловом архиве . Не смотря на прямую связь этого архива с , его также можно найти и в других разделах. Архив можно найти в разделе "рефераты, доклады и презентации", в предмете "информатика, программирование" в общих файлах.

Онлайн просмотр документа "45817"

Текст 4 страницы из документа "45817"

И наоборот, если вам нужно каждый раз выполнять длительную операцию, укажите флаг WT_EXECUTELONGFUNCTION. Для каждой такой операции создается новый поток, который после ее обработки удаляется.

Характеристика

Значение

Начальное коли-чество потоков в пуле

0

Когда поток удаляется

Поток не имеет незавершенных операций ввода/вывода и простаивает некоторое время

Способ ожидания, используемый потоком

Тревожное (alertable) ожидание

Поток просыпается при

Приходе APC-запроса

Таблица 4. Описание работы функции QueueUserWorkItem

Вызов функции при окончании асинхронной операции ввода/вывода

Если в программе выполняется большое количество операций ввода/вывода, лучше, чтобы они выполнялись асинхронно. Это намного повышает производительность приложения и уменьшает время отклика на клиентские запросы. Однако самое сложное в асинхронных операциях – правильно продолжить или завершить их. Можно связать все устройства (файлы) с портом завершения и обрабатывать окончания операций в отдельном потоке. Когда операций много, вновь встает вопрос об организации пула потоков для обработки асинхронных операций ввода/вывода. К счастью, у нас имеется хороший помощник:

BOOL BindIoCompletionCallback(

// хендл файла

HANDLE FileHandle,

// функция обработки завершения запроса

LPOVERLAPPED_COMPLETION_ROUTINE Function,

// зарезервировано

ULONG Flags

);

Эта функция создает порт завершения и связывает его с файлом. Затем функция создает поток, который сразу же начинает ждать (GetQueuedCompletionStatus) окончания асинхронной операции, после чего вызывает определяемую вами функцию для обработки запроса. Вот ее прототип:

VOID CALLBACK FileIOCompletionRoutine(

DWORD dwErrorCode, // код завершения

DWORD dwNumberOfBytesTransfered, // количество переданных байтов

LPOVERLAPPED lpOverlapped // структура OVERLAPPED

);

Хотя прототип этой функции идентичен функции, вызываемой при окончании операций, начатых ReadFileEx и WriteFileEx, не стоит их путать. При использовании BindIoCompletionCallback эта функция вызывается с помощью порта завершения ввода/вывода, тогда как при использовании ReadFileEx и WriteFileEx функция вызывается с помощью APC.

Совершенно непонятно, почему в Microsoft решили не использовать флаги для этой функции, но факт остается фактом. И хотя Рихтер в своей статье, которая упоминалась выше, утверждает, что можно указать флаг WT_EXECUTEINIOTHREAD, это неправда. Вы можете сами посмотреть дизассемблером в ntdll.dll, например, функцию RtlSetIoCompletionCallback и убедиться, что третий параметр в ней просто не используется.

Как видно из прототипа, вы не можете передавать какого-либо дополнительного параметра функции FileIOCompletionRoutine, что может вызвать определенные проблемы. Самым распространенным решением является передача в функцию начала асинхронной операции структуры, производной от OVERLAPPED. Тогда в дополнительных членах структуры можно передавать какую угодно информацию – сама структура OVERLAPPED не копируется, везде передается только указатель на нее.

Характеристика

Значение

Начальное коли-чество потоков в пуле

0

Когда поток удаляется

Поток простаи-вает некоторое время

Способ ожидания, используемый потоком

GetQueuedCompletionStatus

Поток просыпается при

Постановке пакета запроса в очередь порта

Таблица 5. Описание характеристик работы функции BindIoCompletionCallback

Периодический вызов функции

В самом начале статьи я обещал рассказать о новых «таймерных» функциях. До выхода Windows 2000 имелось три механизма периодического вызова пользовательских функций: «оконный» таймер, Multimedia-таймер и ожидающий таймер. У каждого из них были серьезные недостатки, к тому же они не поддерживали обработку запросов в пуле. Новые функции по созданию очереди таймеров более универсальны.

В Windows 2000 появился новый объект – очередь таймеров. Он основан на объекте исполнительной системы "ожидающий таймер", так что в качестве механизма обратного вызова используется APC. Создать объект можно с помощью следующей функции:

HANDLE CreateTimerQueue(VOID);

Она возвращает хендл объекта "очередь таймеров" (queues of timers). После создания очереди в нее можно добавлять новые таймеры. Для этого используется функция CreateTimerQueueTimer:

BOOL CreateTimerQueueTimer(

// указатель на хендл таймера

PHANDLE phNewTimer,

// хендл очереди таймеров

HANDLE TimerQueue,

// функция обратного вызова

WAITORTIMERCALLBACK Callback,

// параметр для функции обратного вызова

PVOID Parameter,

// время задержки перед первым вызовом в милисекундах

DWORD DueTime,

// период в милисекундах

DWORD Period,

// флаги

ULONG Flags

);

Рассмотрим параметры этой функции. Первый параметр возвращает хендл таймера, который можно использовать для вызова функций изменения таймера или его удаления (о них позже). Второй параметр – хендл очереди, созданной функцией CreateTimerQueue. В качестве него можно указать нулевое значение. В этом случае по умолчанию таймер будет добавлен к объекту "очередь таймеров". Третий параметр – адрес функции, которая будет вызвана при переходе таймера в сигнальное состояние. Вот ее прототип:

VOID CALLBACK WaitOrTimerCallback(

PVOID lpParameter, // произвольный параметр

BOOLEAN TimerOrWaitFired // причина вызова

);

Произвольный параметр для нее указывается в функции CreateTimerQueueTimer четвертым параметром. Параметр TimerOrWaitFired для таймеров всегда равен TRUE.

Пятый параметр определяет, сколько времени в миллисекундах пройдет до первого вызова функции WaitOrTimerCallback. Если указать 0, то эта функция будет вызвана практически сразу (примерно так же быстро, как и в случае QueueUserWorkItem).

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

В качестве флагов функции CreateTimerQueueTimer можно указывать все флаги из таблицы 2 и два новых:

Константа

Значение

Описание

WT_EXECUTEINTIMERTHREAD

0x20

Пользовательская функция вызывается в потоке таймера

WT_EXECUTEONLYONCE

8

Пользовательская функция вызывается только один раз

Таблица 6. Флаги функции CreateTimerQueueTimer.

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

При указании флага WT_EXECUTEONLYONCE таймер будет установлен в сигнальное состояние только один раз.

Если вам больше не нужен таймер, его можно удалить из очереди с помощью функции DeleteTimerQueueTimer.

BOOL DeleteTimerQueueTimer(

// хендл очереди таймеров

HANDLE TimerQueue,

// хендл таймера

HANDLE Timer,

// хендл объекта, устанавливаемого в сигнальное состояние после удаления

HANDLE CompletionEvent

);

Если используется очередь по умолчанию, в качестве первого параметра нужно передать NULL. Второй параметр – хендл удаляемого таймера. Третий параметр может принимать следующие значения:

INVALID_HANDLE_VALUE – означает, что вызывающая функция будет заблокирована до тех пор, пока таймер не обработает все текущие запросы. Вы должны быть осторожны с этим значением, так как вызов функции удаления таймера в самой пользовательской функции приведет к взаимоблокировке (deadlock).

NULL – если вы не хотите ожидать завершения обработки всех текущих запросов. Функция DeleteTimerQueueTimer возвратит управление немедленно.

Допустимый хендл объекта – если необходимо синхронизировать окончание обработки текущих запросов. Функция DeleteTimerQueueTimer возвратит управление немедленно, но после окончания обработки запросов объект завершения устанавливается в сигнальное состояние.

Можно сразу удалить всю очередь таймеров с помощью следующей функции:

BOOL DeleteTimerQueueEx(

// хендл очереди таймеров

HANDLE TimerQueue,

// хендл объекта, устанавливаемого в сигнальное состояние после удаления

HANDLE CompletionEvent

);

Если удаляется очередь по умолчанию, в качестве первого параметра нужно передать NULL. Второй параметр имеет то же значение, что и в предыдущей функции DeleteTimerQueueTimer.

Кроме создания и удаления таймера в очереди, можно изменять некоторые его характеристики. Это делается вызовом функции ChangeTimerQueueTimer.

BOOL ChangeTimerQueueTimer(

HANDLE TimerQueue, // хендл очереди таймеров

HANDLE Timer, // хендл таймера

ULONG DueTime, // новое значение задержки перед вызовом

ULONG Period // новое значение периода вызова

);

Функция вопросов не вызывает, однако нужно отметить, что она не оказывает влияния на «одноразовые» (one-shot) таймеры, при создании которых в качестве периода был указан 0.

Характеристика

Значение

Начальное коли-чество потоков в пуле

1

Когда поток удаляется

Когда удаляется последний таймер из очереди

Способ ожидания, используемый потоком

Тревожное (alertable) ожидание

Поток просыпается при

Приходе APC-запроса

Таблица 7. Описание характеристик работы объекта "очередь таймеров".

Вызов функции при переходе объекта в сигнальное состояние

В приложении часто возникает необходимость дождаться какого-либо объекта и выполнить определенное действие. Для многопоточных приложений приходится для каждого такого случая заводить отдельный поток, что нехорошо. В этом случае на помощь приходит функция RegisterWaitForSingleObject. Она позволяет вызывать произвольную пользовательскую функцию после того, как заданный объект перейдет в сигнальное состояние. Причем никаких потоков создавать не нужно, все делается автоматически. Рассмотрим прототип этой функции:

BOOL RegisterWaitForSingleObject(

PHANDLE phNewWaitObject, // адрес хендла объекта ожидания

HANDLE hObject, // хендл объекта

WAITORTIMERCALLBACK Callback, // функция обратного вызова

PVOID Context // произвольный параметр

ULONG dwMilliseconds, // таймаут

ULONG dwFlags // флаги

);

Первый параметр – это указатель на переменную, в которую будет возвращен хендл объекта ожидания. Нужно отметить, что на самом деле это не хендл объекта и его нельзя использовать, например, с функцией CloseHandle. Этот хендл можно использовать только для передачи функции UnregisterWait или UnregisterWaitEx (о них поговорим попозже). В качестве второго параметра нужно передать хендл объекта, перехода которого в сигнальное состояние ожидает эта функция. Третий параметр – адрес функции WaitOrTimerCallback, которую мы описывали раньше. Четвертый параметр – это любое значение, которое просто передается функции WaitOrTimerCallback. В качестве пятого параметра можно указать количество миллисекунд, которое определяет максимальное время ожидания объекта. После его истечения функция WaitOrTimerCallback будет вызвана со вторым параметром, равным TRUE. Если объект перешел в сигнальное состояние до истечения кванта времени, второй параметр функции WaitOrTimerCallback будет равным FASLE.

В качестве флагов можно указывать все описанные ранее значения и одно новое – WT_EXECUTEINWAITTHREAD. Его можно использовать, только если вы выполняете очень короткие операции, функция WaitOrTimerCallback будет вызвана в самом ожидающем потоке. Любая задержка в пользовательской функции приведет к тому, что поток не сможет обработать переход в сигнальное состояние объекта вовремя. Замечу, что при ожидании сигнального состояния события с ручным сбросом (manual reset event) не следует вызывать функцию PulseEvent, если не указаны флаги WT_EXECUTEINWAITTHREAD или WT_EXECUTEONLYONCE, так как в этом случае ожидающий поток не сможет обработать событие перехода объекта в сигнальное состояние.

Для остановки вызова пользовательской функции можно воспользоваться следующими функциями:

BOOL UnregisterWait(

// хендл ожидания

HANDLE WaitHandle

);

BOOL UnregisterWaitEx(

// хендл ожидания

HANDLE WaitHandle,

// хендл объекта, устанавливаемого в сигнальное состояние после удаления

HANDLE CompletionEvent

);

Характеристика

Значение

Начальное коли-чество потоков в пуле

1

Когда поток удаляется

Когда количество объектов равно нулю

Способ ожидания, используемый потоком

WaitForMultipleObjectsEx

Поток просыпается при

Переходе объекта ядра в сигнальное состояние

Таблица 8. Описание работы функции RegisterWaitForSingleObject

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
5160
Авторов
на СтудИзбе
439
Средний доход
с одного платного файла
Обучение Подробнее