Программирование для Windows NT

Работа задачи с несколькими критическими секциями


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

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

Пусть, например, в приложении определены две критические секции, синхронизирующие рисование в двух окнах:

CRITICAL_SECTION csWindowOnePaint;

CRITICAL_SECTION csWindowTwoPaint;

Пусть первая задача выполняет рисование в этих окнах следующим образом:

EnterCriticalSection(&csWindowOnePaint);

EnterCriticalSection(&csWindowTwoPaint);

PaintClientWindow(hWndOne);

PaintClientWindow(hWndTwo);

LeaveCriticalSection(&csWindowTwoPaint);

LeaveCriticalSection(&csWindowOnePaint);

Пусть вторая задача использует другой порядок входа в критические секции и выхода из них:



EnterCriticalSection(&csWindowTwoPaint);

EnterCriticalSection(&csWindowOnePaint);

PaintClientWindow(hWndOne);

PaintClientWindow(hWndTwo);

LeaveCriticalSection(&csWindowOnePaint);

LeaveCriticalSection(&csWindowTwoPaint);

При этом есть вероятность того что когда первая задача войдет в критическую секцию csWindowOnePaint, управление будет передано второй задаче, которая войдет в критическую секцию csWindowTwoPaint и перейдет в состояние ожидания. Она будет ждать освобождения критической секции csWindowOnePaint, занятой первой задачей.

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

Если у вас нет необходимости выполнять рисование во втором окне сразу после рисования в первом окне, вы можете избежать взаимной блокировки задач не только используя правильную последовательность входа и выхода в критические секции, но и выполняя последовательное использование этих критических секций:

// Рисование в первом окне

EnterCriticalSection(&csWindowOnePaint);

PaintClientWindow(hWndOne);

LeaveCriticalSection(&csWindowOnePaint);

// Рисование во втором окне

EnterCriticalSection(&csWindowTwoPaint);

PaintClientWindow(hWndTwo);

LeaveCriticalSection(&csWindowTwoPaint);



Содержание раздела