пятница, 4 февраля 2011 г.

Привязка к потокам объектов пользовательского интерфейса, часть 1: оконные описатели

Это перевод Thread affinity of user interface objects, part 1: Window handles. Автор: Реймонд Чен.

У разных объектов есть разные правила привязки к потокам - но базовые принципы пришли ещё из времён 16-ти битных Windows.

Самым важным элементом пользовательского интерфейса в Windows является, конечно же, окно. Объекты окон имеют привязку к создавшему их потоку. Поток, который создал окно, получает неразрываемую связь с окном. Говоря неформально: поток "владеет" окном. Сообщения отправляются в оконную процедуру только потоку владельцу, и, вообще говоря, модификации этого окна следует проводить только из потока, который создал окно. Хотя оконный менеджер допускает доступ к окну (оконным свойствам, стилям и другим атрибутам вроде оконной процедуры) из любого потока, и такой доступ является потокобезопасным с точки зрения оконного менеджера, но последовательности загрузки-изменения-записи должны быть ограничены только потоком-владельцем. В противном случае вы окажетесь в условиях гонки вроде такой:
wpOld := GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, Cardinal(newWndProc));

function newWndProc(...): LRESULT; stdcall;
begin
  ... 
  CallWindowProc(wpOld, ...); 
  ...
end;
Если подобные модификации деляются беспечно в любом потоке, то между первыми двумя строками может произойти переключение потоков и второй поток может изменить оконную процедуру окна, приводя к тому, что в newWndProc в CallWindowProc будет передаваться неверная "предыдущая" оконная процедура.

Почему тогда Windows позволяет подобные операции потокам, не являющимися владельцем окна? Потому что, как мы все знаем, 16-ти битная Windows была ОС с кооперативной многозадачностью, что означает, что только один поток может быть активен и он не может быть прерван, пока сам этого не захочет. Поэтому указанная выше последовательность кода всегда была безопасна в 16-ти битных Windows. И по соображениям совместимости этот код должен оставаться легальным, даже хотя он более не является безопасным (заметьте, что в попытке ограничить область повреждения, оконный менеджер позволяет менять оконную процедуру только потокам того же процесса, что и поток-владелец окна. Это разумное ограничение, потому что раздельные адресные пространства означают, что адрес функции из другого процесса бессмысленнен в процессе, владеющим окном).

В следующий раз мы посмотрим на контексты устройств (device context).

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.