среда, 24 февраля 2010 г.

Snow

Москву завалило снегом в эти выходные. На парковку у работы пришлось заезжать с разбега, т.к. въезд завалили при расчистке дороги. Коллеги как раз тестировали систему видеонаблюдения, результат ниже.

пятница, 19 февраля 2010 г.

Thread pool sample

Приведу пример кода для RegisterWaitForSingleObject. Для начала создаем событие, по которому задача будет выполнятся. В этом примере это будет Event:
HANDLE render_event_ = CreateEvent( NULL, FALSE, FALSE, NULL );
Создается событие с автопереключением (второй аргумент FALSE), чтобы не вызывать вручную ResetEvent.

Далее вызываем RegisterWaitForSingleObject:
RegisterWaitForSingleObject( &render_wait_obj_, render_event_, RenderCallback, SOME_USER_PARAM, 1000, 0 );
Данным вызовом мы говорим вызывать функцию RenderCallback с аргументом SOME_USER_PARAM по событию render_wait_obj_, но не реже одного раза в 1000 миллисекунд. Возвращается render_wait_obj_ типа HANDLE, которое нужно передать в UnregisterWait, когда больше не нужно выполнять задачи зарегестрированного типа (например, при выходе из программы). Функция RenderCallback имеет следующий вид:
VOID CALLBACK RenderCallback( PVOID lpParameter, BOOLEAN TimerOrWaitFired )
{
// Какие-то действия. Параметр TimerOrWaitFired помогает
// узнать причину вызова RenderCallback.
// Ничего связанного с пулом потоков тут делать не требуется.
}
Когда нужно выполнить задачу RenderCallback просто вызываем SetEvent:
SetEvent( render_event_ );

среда, 17 февраля 2010 г.

Thread pool

При написании программ приходится сталкиваться с ситуациями, когда хотелось бы сделать какую-либо небольшую задачу асинхронной, но создание потока оказывается слишком накладным. Для этого существует концепция пула потоков (thread pool). Вкратце, суть идеи состоит в том, что существует некоторый набор потоков (пул), который может расширятся при необходимости, либо уменьшаться. Разработчику необходимо указывать функции, которые нужно выполнить асинхронно, а реализация пула потоков сама берется выполнить задачу наиболее эффективно используя возможности многоядерных процессоров. Посмотрим на то, что предлагает Windows API.

Простейший сценарий предлагается функцией QueueUserWorkItem. Она принимает указатель на функцию с одним параметром. Указанная задача передается в пул потоков и будет выполнена в соответствии с указанными флагами (флаги помогают пулу потоков определить как лучше выполнить задачу).

Функция RegisterWaitForSingleObject позволяет указать задачу, которая будет выполняться по событию (Event, Mutex, Semaphore, Console input и прочее). Если событие не возникает, то задача выполняется по истечении указанного периода времени. Это, например, удобно использовать для асинхронного отображения видео кадров приходящих по сети. При получении кадра он выводится, а если кадров долго нет, то показывается специальный обновляемый кадр с сообщением о проблеме.

Ещё одна интересная функция — CreateTimerQueueTimer — позволяет создать асинхронный таймер. В этом случае задача ставится в очередь на выполнение регулярно(если другое не задано) через указанный период времени. Уже ясно, что задача выполняется в отдельном потоке, в отличии от обычного таймера Windows.

Интересно отметить, что реализация пула потоков отличается в разных версиях Windows. В Windows XP создается всего 2 потока на 2-х ядерном процессоре, что может оказаться недостаточно для эффективного использования ресурсов. При этом Windows 7, видимо, учитывает не только количество ядер процессора, но и его загрузку в целом. И для той же программы может быть создано более 10 потоков.

вторник, 2 февраля 2010 г.

still here

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