Составители:
Рубрика:
для него процессор (по умолчанию – тот, на котором поток был запущен
первый раз). Для этого предназначена функция SetThreadIdealProcessor.
При использовании NUMA систем следует учитывать, что распреде-
ление доступных процессоров по узлам NUMA системы не обязательно
последовательное – узлы со смежными номерами могут быть с аппарат-
ной точки зрения весьма удалены друг от друга. Функция
GetNumaHighestNodeNumber позволяет определить число NUMA узлов, пос-
ле чего с помощью обращений к функциям GetNumaProcessorNode,
GetNumaNodeProcessorMask и GetNumaAvailableMemoryNode можно определить
размещение узлов NUMA системы на процессорах и доступную каждому
узлу память.
7.2. Взаимодействие процессов и потоков
Материалы, рассматриваемые в этом разделе, могут быть разделены
на две категории – синхронизация потоков и работа с процессами. Они
сгруппированы в силу того, что большая часть методов синхронизации по-
токов может быть успешно применена для потоков, принадлежащих раз-
ным процессам. Кроме того, многие средства взаимодействия потоков,
даже основанные на совместном доступе к данным в едином адресном
пространстве, могут быть использованы в рамках одного вычислительно-
го узла – в случае применения общей, разделяемой процессами, памяти.
7.2.1. Синхронизация потоков
При реализации мультипрограммирования существует проблема од-
новременного конкурирующего доступа нескольких потоков к общим
разделяемым данным. В многопоточных приложениях она особенно акту-
альна, так как вся память процесса является общей и разделяемой всеми
потоками, поэтому конфликты при одновременном доступе могут возни-
кать достаточно часто.
Рассмотрим простейшую программу, в которой несколько потоков
увеличивают на 1 значение элементов общего массива. Так как начальные
значения элементов массива 0, то в результате весь массив должен быть за-
полнен числами, соответствующими числу потоков:
#include <stdio.h>
#include <process.h>
#include <windows.h>
#define THREADS 10
#define ASIZE 10000000
static LONG array[ASIZE];
Разработка параллельных приложений для ОС Windows
231
DWORD dwFlsID;
VOID WINAPI FlsCallback( PVOID lpFlsData )
{
/* при завершении волокна или потока память будет освобождена */
delete[] (int*)lpFlsData;
}
void initialize( void )
{
dwFlsID = FlsAlloc( FlsCallback );
...
}
void fiberstart( void )
{
FlsSetValue( dwFlsID, new int [ 100 ] );
/* здесь мы можем не следить за освобождением выделенной памяти */
}
Остальные функции для работы с FLS аналогичны Tls-функциям как
по описаниям, так и по применению.
7.1.3. Привязка к процессору и системы с неоднородным
доступом к памяти
ОС Windows предоставляет небольшой набор функций, предназна-
ченных для поддержки систем с неоднородным доступом к памяти
(NUMA). К таким функциям относятся средства, обеспечивающие вы-
полнение потоков на конкретных процессорах, и функции, позволяющие
получить информацию о структуре NUMA машины. В некоторых случаях
привязка потоков к процессорам может преследовать и иные цели, чем
поддержка NUMA архитектуры. Так, например, привязка потока к про-
цессору может улучшить использование кэша; на некоторых SMP маши-
нах могут возникать проблемы с использованием таймеров высокого раз-
решения (опирающихся на счетчики процессоров) и т.д.
Привязка потоков к процессору задается с помощью специального
битового вектора (affinity mask), сохраняемого в целочисленной перемен-
ной. Каждый бит этого вектора указывает на возможность исполнения по-
тока на процессоре, номер которого совпадает с номером бита. Таким об-
разом, заданием маски сродства можно ограничить множество процессо-
ров, на которых будет выполняться данный поток. В Windows такие маски
назначаются процессу (функции GetProcessAffinityMask и
SetProcessAffinityMask) и потоку (функция SetThreadAffinityMask). Мас-
ка, назначаемая потоку, должна быть подмножеством маски процесса. По-
мимо ограничения множества процессоров, на которых может исполнять-
ся поток, может быть целесообразно назначить потоку самый «удобный»
230
CIL и системное программирование в Microsoft .NET
230 CIL и системное программирование в Microsoft .NET Разработка параллельных приложений для ОС Windows 231 DWORD dwFlsID; для него процессор (по умолчанию – тот, на котором поток был запущен VOID WINAPI FlsCallback( PVOID lpFlsData ) первый раз). Для этого предназначена функция SetThreadIdealProcessor. { При использовании NUMA систем следует учитывать, что распреде- /* при завершении волокна или потока память будет освобождена */ ление доступных процессоров по узлам NUMA системы не обязательно delete[] (int*)lpFlsData; последовательное – узлы со смежными номерами могут быть с аппарат- } ной точки зрения весьма удалены друг от друга. Функция void initialize( void ) GetNumaHighestNodeNumber позволяет определить число NUMA узлов, пос- { ле чего с помощью обращений к функциям GetNumaProcessorNode, dwFlsID = FlsAlloc( FlsCallback ); GetNumaNodeProcessorMask и GetNumaAvailableMemoryNode можно определить ... размещение узлов NUMA системы на процессорах и доступную каждому } узлу память. void fiberstart( void ) { FlsSetValue( dwFlsID, new int [ 100 ] ); 7.2. Взаимодействие процессов и потоков /* здесь мы можем не следить за освобождением выделенной памяти */ } Материалы, рассматриваемые в этом разделе, могут быть разделены Остальные функции для работы с FLS аналогичны Tls-функциям как на две категории – синхронизация потоков и работа с процессами. Они по описаниям, так и по применению. сгруппированы в силу того, что большая часть методов синхронизации по- токов может быть успешно применена для потоков, принадлежащих раз- 7.1.3. Привязка к процессору и системы с неоднородным ным процессам. Кроме того, многие средства взаимодействия потоков, доступом к памяти даже основанные на совместном доступе к данным в едином адресном ОС Windows предоставляет небольшой набор функций, предназна- пространстве, могут быть использованы в рамках одного вычислительно- ченных для поддержки систем с неоднородным доступом к памяти го узла – в случае применения общей, разделяемой процессами, памяти. (NUMA). К таким функциям относятся средства, обеспечивающие вы- полнение потоков на конкретных процессорах, и функции, позволяющие 7.2.1. Синхронизация потоков получить информацию о структуре NUMA машины. В некоторых случаях При реализации мультипрограммирования существует проблема од- привязка потоков к процессорам может преследовать и иные цели, чем новременного конкурирующего доступа нескольких потоков к общим поддержка NUMA архитектуры. Так, например, привязка потока к про- разделяемым данным. В многопоточных приложениях она особенно акту- цессору может улучшить использование кэша; на некоторых SMP маши- альна, так как вся память процесса является общей и разделяемой всеми нах могут возникать проблемы с использованием таймеров высокого раз- потоками, поэтому конфликты при одновременном доступе могут возни- решения (опирающихся на счетчики процессоров) и т.д. кать достаточно часто. Привязка потоков к процессору задается с помощью специального Рассмотрим простейшую программу, в которой несколько потоков битового вектора (affinity mask), сохраняемого в целочисленной перемен- увеличивают на 1 значение элементов общего массива. Так как начальные ной. Каждый бит этого вектора указывает на возможность исполнения по- значения элементов массива 0, то в результате весь массив должен быть за- тока на процессоре, номер которого совпадает с номером бита. Таким об- полнен числами, соответствующими числу потоков: разом, заданием маски сродства можно ограничить множество процессо- #includeров, на которых будет выполняться данный поток. В Windows такие маски #include назначаются процессу (функции GetProcessAffinityMask и #include SetProcessAffinityMask) и потоку (функция SetThreadAffinityMask). Мас- ка, назначаемая потоку, должна быть подмножеством маски процесса. По- #define THREADS 10 мимо ограничения множества процессоров, на которых может исполнять- #define ASIZE 10000000 ся поток, может быть целесообразно назначить потоку самый «удобный» static LONG array[ASIZE];
Страницы
- « первая
- ‹ предыдущая
- …
- 120
- 121
- 122
- 123
- 124
- …
- следующая ›
- последняя »