| |
ПРОЦЕССЫ
<P>Процесс обычно определяют как экземпляр выполняемой программы. В Win32 процессу отводится 4 Гб адресного пространства. Win32-процессы, в отличие от своих аналогов в MS-DOS и 16-разрядной Windows, инертны, т.е. Win32-процесс ничего не исполняет - просто владеет четырехгигабайтовым адресным пространством, содержащим код и данные исполняемого файла приложения. В это же пространство загружаются код и данные DLL-библиотек, если того требует ЕХЕ-файл. Кроме адресного пространства, процессу принадлежат такие ресурсы, как файлы, динамически выделяемые области памяти и потоки. Ресурсы, создаваемые при жизни процесса, обязательно уничтожаются при его завершении. Чтобы процесс хоть что-нибудь выполнил, в нем нужно создать поток. Именно потоки отвечают за исполнение кода, содержащегося в адресном пространстве процесса. В принципе, один процесс может владеть несколькими потоками, и тогда они "одновременно" исполняют код в адресном пространстве процесса. Каждый поток должен располагать собственным набором регистров процессора и собственным стеком, а каждый процесс - минимум одним потоком. Если бы у процесса не было ни одного потока, ему бы нечего было делать, и система автоматически уничтожила бы его вместе с выделенным ему адресным пространством.<BR><BR>Чтобы потоки работали, операционная система отводит каждому из них определенное процессорное время. Выделяя потокам отрезки времени, называемые квантами, по принципу карусели, она создает иллюзию одновременного выполнения потоков (рис.1).<BR><BR>При создании Win32-процесса, первый поток создается системой автоматически. Далее этот поток может породить другие потоки, те в свою очередь - новые и т.д.<BR><IMG height=182 alt="" src="/-3.gif" width=177 border=0></P> <P>Рис. 1. Операционная система выделяет потокам кванты времени по принципу карусели</P> <P>ПОТОКИ</P> <P>Поток (thread) определяет последовательность исполнения кода в процессе. При инициализации процесса система всегда создает первичный поток. Большинство приложений обходится единственным первичным потоком, однако процессы могут создавать дополнительные потоки, что позволяет добиваться минимального простоя процессора.<BR><BR>Например, в электронных таблицах нужно пересчитывать данные при изменении пользователем содержимого ячеек. Пересчет сложной таблицы может занять несколько секунд, но тщательно продуманное приложение не должно тратить время на эту операцию после каждого изменения. Вместо этого следует выделить функциональный блок повторных расчетов в отдельный поток с более низким приоритетом. Таким образом, пока пользователь набирает данные, исполняется первичный поток, т. е. система не выделяет процессорного времени потоку, отвечающему за пересчет. Возникнет пауза - система приостановит выполнение первичного потока, ожидающего ввода данных, и отдает процессорное время блоку повторных расчетов. При возобновлении ввода данных первичный поток, имеющий более высокий приоритет, вытеснит поток, занимающийся пересчетом. Создание дополнительного потока делает программу "отзывчивой" на действия пользователя.<BR><BR>Еще одно применение многопоточности в компонентах MDI - приложения с многодокументным интерфейсом (multiple document interface, MDI), где каждое дочернее MDI-окно поддерживается отдельным потоком. Если один из таких потоков входит в бесконечный цикл или начинает выполнять длительную операцию, пользователь может переключиться в другое дочернее MDI окно и поработать с ним, пока предыдущее выполняет поставленную задачу. </P> <P>Стек потока<BR><BR>Каждому потоку выделяется собственный стек в адресном пространстве процесса. При использовании статических и глобальных переменных не исключена возможность одновременного обращения к ним из нескольких потоков, что может повредить значения переменных. Локальные и автоматические переменные создаются в стеке потока, а значит, они в гораздо меньшей степени подвержены "вредному влиянию" других потоков.</P> <P>Распределение процессорного времени между потоками<BR>Операционная система с вытесняющей многозадачностью должна использовать тот или иной алгоритм, позволяющий ей распределять процессорное время между потоками. Рассмотрим алгоритм, применяемый в Windows NT и Windows 95х.<BR><BR>Система выделяет процессорное время всем активным потокам, исходя из их уровней приоритета, которые варьируются от 0 (низший) до 31 (высший). Нулевой уровень присваивается в системе особому потоку обнуления страниц (zero page thread), обнуляющему свободные страницы при отсутствии других потоков, требующих внимания со стороны системы. Ни один поток, кроме него, не может иметь нулевой уровень приоритета.<BR><BR>Когда система подключает процессор к потоку, он обрабатывает потоки с одинаковым приоритетом как равноправные. На процессор подается первый поток с приоритетом 31, по истечении его кванта времени система переключает процессор на выполнение следующего потока с тем же приоритетом. Как только все потоки с приоритетом 31 получат по кванту времени, система вновь подаст на процессор первый поток с приоритетом 31. Если в системе за каждым процессором закреплен хотя бы один поток с приоритетом 31, остальные потоки с более низким приоритетом никогда не получат доступ к процессору и поэтому не будут выполняться. Такая ситуация называется перегрузкой. Она возникает, когда некоторые потоки так интенсивно используют процессорное время, что остальные практически не работают.<BR><BR>При отсутствии потоков с приоритетом 31, система переходит к потокам с приоритетом 30 и т. д.<BR>На первый взгляд, в системе, организованной таким образом, у потоков с низким приоритетом нет ни единого шанса на исполнение. Однако, зачастую, потоки как раз и не нужно выполнять. Например, если первичный поток процесса вызывает GetMessage, а система "видит", что никаких сообщений пока нет, она приостанавливает его выполнение, отнимает остаток неиспользованного времени и тут же подключает к процессору другой, ожидающий поток. И пока в системе не появится сообщений для потока, он будет простаивать - система не станет тратить на него время. Как только в очереди этого потока появляется сообщение, система сразу же подключает его к процессору, если только в этот момент не выполняется поток с более высоким приоритетом.<BR><BR>Допустим, процессор исполняет поток с приоритетом 5, и тут система обнаруживает, что поток с более высоким приоритетом готов к выполнению. Система остановит поток с более низким приоритетом, даже если не истек отведенный ему квант процессорного времени, и подключит к процессору поток с более высоким приоритетом выдав ему полный квант времени. Так что потоки с более высоким приоритетом всегда вытесняют потоки с более низким приоритетом.</P> <P> Присвоение уровней приоритета в Win32<BR><BR>Система устанавливает уровни приоритета потоков в два этапа. На первом - процессу присваивается определенный класс приоритета, который говорит системе, какой приоритет нужен данному процессу по сравнению с другими процессами. На втором - потокам, принадлежащим этому процессу, присваиваются относительные уровни приоритета.</P> <P>Классы приоритета процессов<BR><BR>Win32 поддерживает 4 класса приоритетов:</P> <P> <TABLE cellSpacing=1 cellPadding=1 width="75%" border=0>
<TR class=TableHead1> <TD>Класс</TD> <TD>Флаг в CreateProcess</TD> <TD>Уровень</TD></TR> <TR> <TD><FONT color=#ffcc00>Idle</FONT></TD> <TD>IDLE_PRIORITY_CLASS</TD> <TD>4</TD></TR> <TR> <TD><FONT color=#ffcc00>Normal</FONT></TD> <TD>NORMAL_PRIORITY_CLASS</TD> <TD>8</TD></TR> <TR> <TD><FONT color=#ffcc00>High</FONT></TD> <TD>HIGH_PRIORITY_CLASS</TD> <TD>13</TD></TR> <TR> <TD><FONT color=#ffcc00>Realtime</FONT></TD> <TD>REALTIME_PRIORITY_CLASS</TD> <TD>24</TD></TR></TABLE></P> <P>Любой поток, созданный в процессе с обычным классом приоритета, получает уровень приоритета 8. Вызывая CreateProcess, большинство приложений должны либо использовать флаг NORMAL_PRIORITY_CLASS, либо вообще не указывать класс приоритета. В последнем случае система присваивает процессу класс normal - если только родительский процесс не имеет класса idle (тогда дочерний процесс тоже получает класс приоритета idle).<BR><BR>Когда пользователь работает с каким-то процессом, он считается активным (foreground), а остальные процессы - фоновыми (background). В Windows NT, когда обычный процесс становится активным, система увеличивает кванты времени, выделяемые всем его потокам. Если потоки обычного процесса получают 15 мс процессорного времени, то, как только этот процесс становится активным, система выдает им 45 мс.<BR><BR>В Windows 9х, когда обычный процесс становится активным, система поступает иначе - повышает приоритет потока на 1, т. е. уровень приоритета потока увеличивается с 8 до 9. А когда процесс "уходит" в фон, приоритет потока автоматически снижается на 1.<BR><BR>Причина таких изменений в активных процессах проста: система добивается отзывчивости. Если бы приоритеты потоков не менялись, то и обычный процесс фоновой печати, и обычный, но активный процесс, принимающий пользовательский ввод, - оба одинаково конкурировали бы за процессорное время. И тогда пользователь, набирая текст в активном приложении, заметил бы, что текст появляется на экране рывками. Но так как система повышает уровни приоритета активного процесса, они вытесняют потоки обычных процессов, работающих в фоновом режиме.<BR><BR>Приоритет idle идеален для приложений, занимающихся мониторингом системы, для экранных заставок.<BR><BR>Класс приоритета high следует использовать только при крайней необходимости. С высоким приоритетом выполняется Explorer. Окна Explorer можно открывать, даже когда все потоки с более низким приоритетом зависают в бесконечных циклах. Обладая более высоким приоритетом, потоки Explorer вытесняют поток, исполняющий бесконечный цикл, и дают возможность закрыть зависший процесс.<BR><BR>Классом приоритета Realtime почти никогда не стоит пользоваться, это чрезвычайно высокий приоритет, и поскольку большинство потоков в системе (включая те, что управляют самой системой) имеют более низкий приоритет, процесс с таким классом окажет на них сильное влияние. Так, системные потоки, контролирующие мышь и клавиатуру, перехват Alt+Ctrl+Del, - все они оперируют при более низком классе приоритета. При перемещении мыши, поток, реагирующий на ее движение, будет вытеснен потоком с приоритетом realtime. А это повлияет на характер перемещения курсора мыши - он станет двигаться рывками. Класс приоритета realtime используют только в программе, напрямую обращающейся к оборудованию, или если приложение выполняет быстротечную операцию, которую нельзя прерывать ни при каких обстоятельствах.</P> <P>Установка относительного приоритета потока<BR><BR>При создании потока уровень его приоритета соответствует классу приоритета процесса. Например, первичный поток процесса с классом high получает начальное значение уровня приоритета 13. Но уровень приоритета отдельного потока можно повысить или понизить. Но приоритет потока всегда относителен классу приоритета его процесса.<BR><BR>В момент создания потока начальное значение его относительного приоритета равно Normal. Правила установки приоритета для потоков в рамках какого-либо процесса аналогичны правилам установки приоритета для потоков разных процессов. Устанавливать приоритет Highest следует, только если это абсолютно необходимо для корректного выполнения данного потока. Иначе потоки с более низкими приоритетами будут вытеснены потоками с более высокими приоритетами.<BR><BR>В табл. 1 показано, как система определяет базовый уровень приоритета потока, комбинируя класс приоритета процесса с относительным приоритетом потока.<BR><BR> Таблица 1<BR>Определение базового уровня приоритета потока</P> <P> <TABLE cellSpacing=1 cellPadding=1 width="75%" border=0>
<TR class=TableHead1> <TD></TD> <TD colSpan=5>Класс приоритета потока</TD></TR> <TR class=TableHead1> <TD>Относительный приоритет потока</TD> <TR> <TD></TD> <TD><FONT color=#ffcc00>Normal</FONT></TD> <TD><FONT color=#ffcc00>High</FONT></TD> <TD><FONT color=#ffcc00>Realtime</FONT></TD></TR> <TR> <TD><FONT color=#ffcc00>Time critical</FONT></TD> <TD>15</TD> <TD>15</TD> <TD>15</TD> <TD>31</TD></TR> <TR> <TD><FONT color=#ffcc00>Highest</FONT></TD> <TD>6</TD> <TD>10</TD> <TD>15</TD> <TD>26</TD></TR> <TR> <TD><FONT color=#ffcc00>Above normal</FONT></TD> <TD>5</TD> <TD>9</TD> <TD>14</TD> <TD>25</TD></TR> <TR> <TD><FONT color=#ffcc00>Normal</FONT></TD> <TD>4</TD> <TD>8</TD> <TD>13</TD> <TD>24</TD></TR> <TR> <TD><FONT color=#ffcc00>Below normal</FONT></TD> <TD>3</TD> <TD>7</TD> <TD>12</TD> <TD>23</TD></TR> <TR> <TD><FONT color=#ffcc00>Lowest</FONT></TD> <TD>2</TD> <TD>6</TD> <TD>11</TD> <TD>22</TD></TR> <TR> <TD><FONT color=#ffcc00>Idle</FONT></TD> <TD>1</TD> <TD>1</TD> <TD>1</TD> <TD>16</TD></TR></TABLE></P> <P><BR>Таблица 1 показывает приоритеты потоков для фоновых процессов. В Windows NT, когда процесс становится активным, приоритеты не изменяются - меняются кванты времени, выделяемые потокам. Windows 9х, когда процесс становится активным, увеличивает приоритет потоков lowest, below normal, normal и above normal на 1 единицу, но не меняет приоритет потоков idle и time critical.<BR></P>
|