Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 113 стр.

UptoLike

или /MDd (свойства проекта Configuration Properties|C/C++|Code
Generation|Runtime Library).
6.2.4.2. Работа с потоками
Наличие специальных потоко-безопасных версий библиотек требует
использования специальных функций для создания и завершения потоков,
принадлежащих не системному API, а библиотеке времени исполнения.
Так, вместо функций Win32 API CreateThread, ExitThread необходимо ис-
пользовать библиотечные функции _beginthread,
_endthread или _beginthreadex, _endthreadex. Это требование связано с тем,
что при создании нового потока необходимо, помимо выполнения опреде-
ленных действий по созданию потока со стороны операционной системы,
инициализировать специфичные структуры данных, обслуживающих по-
токо-безопасные версии функций библиотеки времени исполнения:
unsigned __stdcall ThreadProc( void *param )
{
/* вновь созданный поток будет выполнять эту функцию */
Sleep( 1000 );
delete[] (int*)param;
return 0;
/* завершение функции = завершение потока */
}
int main( void )
{
HANDLE hThread;
unsigned dwThread;
/* создаем новый поток */
hThread = (HANDLE)_beginthreadex
(NULL, 0, ThreadProc, new int [128], 0, &dwThread
);
/* код в этом месте может выполняться
одновременно с кодом функции потока ThreadProc,
планирование потоков осуществляется системой
*/
/* дождаться завершения созданного потока */
WaitForSingleObject( hThread, INFINITE );
CloseHandle( hThread );
return 0;
}
Основы многозадачности
213
6.2.4. Основы использования потоков и волокон
Для реализации мультипрограммирования или мультипроцессирова-
ния на однотипных устройствах можно применять процессы, потоки и во-
локна. Разница между ними связана с возможностью обмена данными: ад-
ресное пространство процессов изолировано друг от друга, поэтому взаи-
модействие затруднено; потоки находятся в общем адресном пространст-
ве процесса и могут легко взаимодействовать друг с другом; волокна отча-
сти аналогичны потокам, но планирование волокон выполняется непо-
средственно приложением, а не операционной системой.
6.2.4.1. Потоко-безопасные и небезопасные функции
При реализации многопоточного приложения следует учитывать воз-
можные побочные эффекты. Наличие таких эффектов обусловлено реали-
зацией библиотеки времени исполнения: она содержит много функций
(в том числе внутренних, обеспечивающих семантику языка программиро-
вания), являющихся потоко-небезопасными. Примеры таких функций –
стандартная процедура strtok, операторы new и delete или функции
malloc, calloc, free и так далее. Фактически любая стандартная функция,
оперирующая статическими переменными, объектами или данными, мо-
жет являться потоко-небезопасной в силу того, что два потока могут полу-
чить одновременный конкурирующий доступ к этим данным и в итоге раз-
рушить их. Существует несколько подходов к решению этой проблемы:
Можно предоставить потоко-безопасные аналоги (например,
strtok_r, являющийся в Linux потоко-безопасным аналогом
функции strtok).
Можно переписать код всех потоко-небезопасных функций так,
чтобы они вместо глобальных объектов использовали локаль-
ную для потока память или синхронизировали доступ к общим
данным.
В Windows принят второй подход, однако, с некоторой оговоркой.
Потоко-безопасные версии функций более ресурсо- и время- емкие, чем
обычные. В итоге используется два вида библиотек: один для однопоточ-
ных приложений, другой для многопоточных. Следует отметить, что вы-
бор той или иной библиотеки определяется, как правило, свойствами про-
екта (параметрами компилятора), а вовсе не кодом приложения. Поэтому
при разработке многопотокового приложения важно проследить, чтобы
при компиляции использовалась правильная версия библиотеки, во избе-
жание возникновения трудно диагностируемых ошибок, проявляющихся
в самых разных и совершенно «невинных» на первый взгляд местах кода.
В случае Visual Studio однопоточные версии библиотек выбираются клю-
чами /ML или /MLd компилятора, а многопоточные ключами /MT, /MD, /MTd
212
CIL и системное программирование в Microsoft .NET
212                         CIL и системное программирование в Microsoft .NET   Основы многозадачности                                                213


6.2.4. Основы использования потоков и волокон                                   или /MDd (свойства проекта Configuration Properties|C/C++|Code
                                                                                Generation|Runtime Library).
     Для реализации мультипрограммирования или мультипроцессирова-
ния на однотипных устройствах можно применять процессы, потоки и во-            6.2.4.2. Работа с потоками
локна. Разница между ними связана с возможностью обмена данными: ад-                  Наличие специальных потоко-безопасных версий библиотек требует
ресное пространство процессов изолировано друг от друга, поэтому взаи-          использования специальных функций для создания и завершения потоков,
модействие затруднено; потоки находятся в общем адресном пространст-            принадлежащих не системному API, а библиотеке времени исполнения.
ве процесса и могут легко взаимодействовать друг с другом; волокна отча-        Так, вместо функций Win32 API CreateThread, ExitThread необходимо ис-
сти аналогичны потокам, но планирование волокон выполняется непо-               пользовать           библиотечные         функции           _beginthread,
средственно приложением, а не операционной системой.                            _endthread или _beginthreadex, _endthreadex. Это требование связано с тем,
                                                                                что при создании нового потока необходимо, помимо выполнения опреде-
6.2.4.1. Потоко-безопасные и небезопасные функции                               ленных действий по созданию потока со стороны операционной системы,
      При реализации многопоточного приложения следует учитывать воз-           инициализировать специфичные структуры данных, обслуживающих по-
можные побочные эффекты. Наличие таких эффектов обусловлено реали-              токо-безопасные версии функций библиотеки времени исполнения:
зацией библиотеки времени исполнения: она содержит много функций
(в том числе внутренних, обеспечивающих семантику языка программиро-                 unsigned __stdcall ThreadProc( void *param )
вания), являющихся потоко-небезопасными. Примеры таких функций –                     {
стандартная процедура strtok, операторы new и delete или функции                       /* вновь созданный поток будет выполнять эту функцию */
malloc, calloc, free и так далее. Фактически любая стандартная функция,                Sleep( 1000 );
оперирующая статическими переменными, объектами или данными, мо-                       delete[] (int*)param;
жет являться потоко-небезопасной в силу того, что два потока могут полу-               return 0;
чить одновременный конкурирующий доступ к этим данным и в итоге раз-                   /* завершение функции = завершение потока */
рушить их. Существует несколько подходов к решению этой проблемы:                    }
         • Можно предоставить потоко-безопасные аналоги (например,
           strtok_r, являющийся в Linux потоко-безопасным аналогом                   int main( void )
           функции strtok).                                                          {
         • Можно переписать код всех потоко-небезопасных функций так,                  HANDLE    hThread;
           чтобы они вместо глобальных объектов использовали локаль-                   unsigned dwThread;
           ную для потока память или синхронизировали доступ к общим                   /* создаем новый поток */
           данным.                                                                     hThread = (HANDLE)_beginthreadex
      В Windows принят второй подход, однако, с некоторой оговоркой.                     (NULL, 0, ThreadProc, new int [128], 0, &dwThread
Потоко-безопасные версии функций более ресурсо- и время- емкие, чем                    );
обычные. В итоге используется два вида библиотек: один для однопоточ-                  /* код в этом месте может выполняться
ных приложений, другой для многопоточных. Следует отметить, что вы-                       одновременно с кодом функции потока ThreadProc,
бор той или иной библиотеки определяется, как правило, свойствами про-                    планирование потоков осуществляется системой
екта (параметрами компилятора), а вовсе не кодом приложения. Поэтому                   */
при разработке многопотокового приложения важно проследить, чтобы                      /* дождаться завершения созданного потока */
при компиляции использовалась правильная версия библиотеки, во избе-                   WaitForSingleObject( hThread, INFINITE );
жание возникновения трудно диагностируемых ошибок, проявляющихся                       CloseHandle( hThread );
в самых разных и совершенно «невинных» на первый взгляд местах кода.                   return 0;
В случае Visual Studio однопоточные версии библиотек выбираются клю-                 }
чами /ML или /MLd компилятора, а многопоточные ключами /MT, /MD, /MTd