Составители:
Рубрика:
Собственно работа с критическими секциями сводится к двум основ-
ным функциям: функция EnterCriticalSection, которая соответствует
входу в критическую секцию, при необходимости с ожиданием, не огра-
ниченным по времени (!); и функция LeaveCriticalSection, которая соот-
ветствует выходу из этой секции, возможно с пробуждением потоков,
ожидающих ее освобождения. При этом система исключает вход в крити-
ческую секцию всех остальных потоков процесса, в то время как поток,
уже вошедший в данную секцию, может входить в нее рекурсивно – надо
лишь, чтобы число выходов из секции соответствовало числу входов:
#include <stdio.h>
#include <process.h>
#define _WIN32_WINNT 0x0403
#include <windows.h>
#define THREADS 10
#define ASIZE 10000000
static LONG array[ASIZE];
static CRITICAL_SECTION CS;
unsigned __stdcall ThreadProc( void *param )
{
int i;
for ( i = 0; i < ASIZE; i++ ) {
EnterCriticalSection( &CS );
array[i]++;
LeaveCriticalSection( &CS );
}
return 0;
}
int main( void )
{
HANDLE hThread[THREADS];
unsigned dwThread;
int i, errs;
InitializeCriticalSectionAndSpinCount( &CS, 100 );
for ( i = 0; i < THREADS; i++ )
hThread[i] = (HANDLE)_beginthreadex(
NULL, 0, ThreadProc, (void*)i, 0, &dwThread );
WaitForMultipleObjects( THREADS, hThread, TRUE, INFINITE );
for ( i = 0; i < THREADS; i++ ) CloseHandle( hThread[i] );
Разработка параллельных приложений для ОС Windows
235
в том числе со сравнением (InterlockedCompareExchange,
InterlockedCompareExchangePointer).
В приведенном выше примере было бы достаточно заменить опера-
тор array[i]++ на вызов функции InterlockedIncrement:
unsigned __stdcall ThreadProc( void *param )
{
int i;
for ( i = 0; i < ASIZE; i++ ) InterlockedIncrement(array+i);
return 0;
}
Еще несколько функций предназначены для работы с односвязными
LIFO списками. Функция InitializeSListHead подготавливает начальный
указатель на LIFO список, функция InterlockedPushEntrySList добавляет но-
вую запись в список, функция InterlockedPopEntrySList извлекает из списка
последнюю добавленную запись и функция InterlockedFlushSList очищает
список. Операции изменения указателей в списке являются атомарными.
7.2.1.2. Критические секции
Термин «критическая секция» обозначает некоторый фрагмент кода,
который должен выполняться в исключительном режиме – никакие дру-
гие потоки и процессы не должны выполнять этот же фрагмент в то же
время. В некоторых операционных системах для однопроцессорных ма-
шин вход в критическую секцию просто блокирует работу планировщика
до выхода из секции. Этот подход не всегда эффективен: нахождение по-
тока в критической секции не должно влиять на возможность исполнения
кода, не принадлежащего именно данной критической секции, другими
потоками, особенно на многопроцессорных машинах.
В Windows предусмотрен специальный тип данных, называемый
CRITICAL_SECTION и предназначенный для реализации критических сек-
ций. В приложении может существовать произвольное количество данных
этого типа, реализующих различные критические секции; равно как
несколько секций кода могут использовать один общий объект
CRITICAL_SECTION.
Существуют четыре основных функции для работы с критическими
секциями; перед использованием критическая секция должна быть ини-
циализирована с помощью функции InitializeCriticalSection. Объект
CRITICAL_SECTION, принадлежащий пользовательскому процессу, может
использовать в своей реализации объекты ядра для ожидания; эти объек-
ты могут создаваться по мере надобности, и для окончательного освобож-
дения ресурсов, после использования критической секции она должна
быть удалена с помощью функции DeleteCriticalSection.
234
CIL и системное программирование в Microsoft .NET
234 CIL и системное программирование в Microsoft .NET Разработка параллельных приложений для ОС Windows 235
в том числе со сравнением (InterlockedCompareExchange, Собственно работа с критическими секциями сводится к двум основ-
InterlockedCompareExchangePointer). ным функциям: функция EnterCriticalSection, которая соответствует
В приведенном выше примере было бы достаточно заменить опера- входу в критическую секцию, при необходимости с ожиданием, не огра-
тор array[i]++ на вызов функции InterlockedIncrement: ниченным по времени (!); и функция LeaveCriticalSection, которая соот-
ветствует выходу из этой секции, возможно с пробуждением потоков,
unsigned __stdcall ThreadProc( void *param ) ожидающих ее освобождения. При этом система исключает вход в крити-
{ ческую секцию всех остальных потоков процесса, в то время как поток,
int i; уже вошедший в данную секцию, может входить в нее рекурсивно – надо
for ( i = 0; i < ASIZE; i++ ) InterlockedIncrement(array+i); лишь, чтобы число выходов из секции соответствовало числу входов:
return 0;
} #include
Еще несколько функций предназначены для работы с односвязными #include
LIFO списками. Функция InitializeSListHead подготавливает начальный #define _WIN32_WINNT 0x0403
указатель на LIFO список, функция InterlockedPushEntrySList добавляет но- #include
вую запись в список, функция InterlockedPopEntrySList извлекает из списка
последнюю добавленную запись и функция InterlockedFlushSList очищает #define THREADS 10
список. Операции изменения указателей в списке являются атомарными. #define ASIZE 10000000
static LONG array[ASIZE];
7.2.1.2. Критические секции static CRITICAL_SECTION CS;
Термин «критическая секция» обозначает некоторый фрагмент кода,
который должен выполняться в исключительном режиме – никакие дру- unsigned __stdcall ThreadProc( void *param )
гие потоки и процессы не должны выполнять этот же фрагмент в то же {
время. В некоторых операционных системах для однопроцессорных ма- int i;
шин вход в критическую секцию просто блокирует работу планировщика for ( i = 0; i < ASIZE; i++ ) {
до выхода из секции. Этот подход не всегда эффективен: нахождение по- EnterCriticalSection( &CS );
тока в критической секции не должно влиять на возможность исполнения array[i]++;
кода, не принадлежащего именно данной критической секции, другими LeaveCriticalSection( &CS );
потоками, особенно на многопроцессорных машинах. }
В Windows предусмотрен специальный тип данных, называемый return 0;
CRITICAL_SECTION и предназначенный для реализации критических сек- }
ций. В приложении может существовать произвольное количество данных
этого типа, реализующих различные критические секции; равно как int main( void )
несколько секций кода могут использовать один общий объект {
CRITICAL_SECTION. HANDLE hThread[THREADS];
Существуют четыре основных функции для работы с критическими unsigned dwThread;
секциями; перед использованием критическая секция должна быть ини- int i, errs;
циализирована с помощью функции InitializeCriticalSection. Объект InitializeCriticalSectionAndSpinCount( &CS, 100 );
CRITICAL_SECTION, принадлежащий пользовательскому процессу, может for ( i = 0; i < THREADS; i++ )
использовать в своей реализации объекты ядра для ожидания; эти объек- hThread[i] = (HANDLE)_beginthreadex(
ты могут создаваться по мере надобности, и для окончательного освобож- NULL, 0, ThreadProc, (void*)i, 0, &dwThread );
дения ресурсов, после использования критической секции она должна WaitForMultipleObjects( THREADS, hThread, TRUE, INFINITE );
быть удалена с помощью функции DeleteCriticalSection. for ( i = 0; i < THREADS; i++ ) CloseHandle( hThread[i] );
Страницы
- « первая
- ‹ предыдущая
- …
- 122
- 123
- 124
- 125
- 126
- …
- следующая ›
- последняя »
