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

UptoLike

int i,j,k, from, to;
from = ( m_stripused++ ) * m_stripsize;
to = from + m_stripsize;
...
Здесь потенциально возможна ситуация, когда несколько потоков
одновременно начнут выполнять этот код и получат идентичные номера
полос. В этом месте самым эффективным было бы использование атомар-
ных операций для увеличения значения поля m_stripused. Для этого фраг-
мент надо переписать:
public static void ThreadProc()
{
int i,j,k, from, to;
from = (Interlocked.Increment(ref m_stripused) – 1 ) * m_stripsize;
to = from + m_stripsize;
...
7.3.4.2. Синхронизация потоков
Основные средства взаимной синхронизации потоков в .NET обла-
дают заметным сходством со средствами операционной системы. Среди
них можно выделить:
Мониторы, близкие к критическим секциям Win32 API.
События и мьютексы, имеющие соответствующие аналоги сре-
ди объектов ядра.
Плюс дополнительный достаточно универсальный синхронизи-
рующий объект, обеспечивающий множественный доступ пото-
ков по чтению и исключительный – по записи.
Последний синхронизирующий объект ReaderWriterLock закрывает
очень типичный класс задач синхронизации – для многих объектов явля-
ется совершенно корректным конкурентный доступ для чтения и требу-
ются исключительные права для изменения данных. Причина в том, что
изменение сложных объектов осуществляется не атомарно, поэтому во
время постепенного внесения изменений объект кратковременно пребы-
вает в некорректном состоянии – при этом должен быть исключен
не только доступ других потоков, пытающихся внести изменения, но даже
потоков, осуществляющих чтение.
Мониторы
Мониторы в .NET являются аналогами критических секций в Win32
API. Использование мониторов достаточно эффективно (это один из са-
мых эффективных механизмов) и удобно настолько, что в .NET был пре-
дусмотрен механизм, который позволяет использовать практически лю-
бой объект, хранящийся в управляемой куче, для синхронизации доступа.
Разработка параллельных приложений для ОС Windows
261
public delegate void AsyncProcCallback ( GreetingData gd );
class TestApp {
public static void Main() {
GreetingData gd = new GreetingData( “Hello!!!” );
AsyncProcCallback apd = new AsyncProcCallback(
GreetingData.Invoke );
IAsyncResult ar = apd.BeginInvoke( gd, null, null );
ar.AsyncWaitHandle.WaitOne();
}
}
}
Данный пример иллюстрирует вызов асинхронной процедуры с ис-
пользованием метода BeginInvoke и альтернативный механизм ожидания
завершения – с использованием внутреннего объекта AsyncWaitHandle
(класса WaitHandle), благодаря которому, собственно говоря, становится
возможен вызов асинхронной процедуры, обслуживающей завершение
обработки данной процедуры.
В этом смысле асинхронный вызов процедур с помощью BeginInvoke
очень близок к обработке асинхронных операций ввода-вывода.
7.3.4. Синхронизация и изоляция потоков
Проблемы, встающие перед разработчиками многопоточных прило-
жений .NET, очень похожи на проблемы разработчиков приложений Win32
API. Соответственно, .NET предоставляет в значительной мере близкий
набор средств взаимодействия потоков и их взаимной синхронизации.
К этим средствам относятся атомарные операции, локальная для по-
тока память, синхронизирующие примитивы и таймеры. Их применение в
основе своей похоже на применение аналогичных средств API.
7.3.4.1. Атомарные операции
Платформа .NET предоставляет, аналогично базовой операционной
системе Windows, набор некоторых основных операций над целыми числами
(int и long), которые могут выполняться атомарно. Для этого предусмотре-
ны четыре статических метода класса System.Threading.Interlocked, а имен-
но Increment, Decrement, Exchange и CompareExchange. Применение этих мето-
дов аналогично соответствующим Interlocked... процедурам Win32 API.
Возвращаясь к примеру использования потоков для умножения мат-
риц, можно выделить один момент, требующий исправления: самое нача-
ло процедуры потока, там, где определяется номер полосы:
public static void ThreadProc()
{
260
CIL и системное программирование в Microsoft .NET
260                          CIL и системное программирование в Microsoft .NET   Разработка параллельных приложений для ОС Windows                      261


        public delegate void AsyncProcCallback ( GreetingData gd );                     int     i,j,k, from, to;
        class TestApp {                                                                 from = ( m_stripused++ ) * m_stripsize;
          public static void Main() {                                                   to = from + m_stripsize;
            GreetingData gd = new GreetingData( “Hello!!!” );                           ...
            AsyncProcCallback apd = new AsyncProcCallback(                           Здесь потенциально возможна ситуация, когда несколько потоков
               GreetingData.Invoke );                                            одновременно начнут выполнять этот код и получат идентичные номера
            IAsyncResult ar = apd.BeginInvoke( gd, null, null );                 полос. В этом месте самым эффективным было бы использование атомар-
            ar.AsyncWaitHandle.WaitOne();                                        ных операций для увеличения значения поля m_stripused. Для этого фраг-
          }                                                                      мент надо переписать:
        }
     }                                                                                public static void ThreadProc()
     Данный пример иллюстрирует вызов асинхронной процедуры с ис-                     {
пользованием метода BeginInvoke и альтернативный механизм ожидания                      int     i,j,k, from, to;
завершения – с использованием внутреннего объекта AsyncWaitHandle                       from = (Interlocked.Increment(ref m_stripused) – 1 ) * m_stripsize;
(класса WaitHandle), благодаря которому, собственно говоря, становится                  to = from + m_stripsize;
возможен вызов асинхронной процедуры, обслуживающей завершение                           ...
обработки данной процедуры.
     В этом смысле асинхронный вызов процедур с помощью BeginInvoke              7.3.4.2. Синхронизация потоков
очень близок к обработке асинхронных операций ввода-вывода.                           Основные средства взаимной синхронизации потоков в .NET обла-
                                                                                 дают заметным сходством со средствами операционной системы. Среди
7.3.4. Синхронизация и изоляция потоков                                          них можно выделить:
     Проблемы, встающие перед разработчиками многопоточных прило-                         • Мониторы, близкие к критическим секциям Win32 API.
жений .NET, очень похожи на проблемы разработчиков приложений Win32                       • События и мьютексы, имеющие соответствующие аналоги сре-
API. Соответственно, .NET предоставляет в значительной мере близкий                         ди объектов ядра.
набор средств взаимодействия потоков и их взаимной синхронизации.                         • Плюс дополнительный достаточно универсальный синхронизи-
     К этим средствам относятся атомарные операции, локальная для по-                       рующий объект, обеспечивающий множественный доступ пото-
тока память, синхронизирующие примитивы и таймеры. Их применение в                          ков по чтению и исключительный – по записи.
основе своей похоже на применение аналогичных средств API.                            Последний синхронизирующий объект ReaderWriterLock закрывает
                                                                                 очень типичный класс задач синхронизации – для многих объектов явля-
7.3.4.1. Атомарные операции                                                      ется совершенно корректным конкурентный доступ для чтения и требу-
     Платформа .NET предоставляет, аналогично базовой операционной               ются исключительные права для изменения данных. Причина в том, что
системе Windows, набор некоторых основных операций над целыми числами            изменение сложных объектов осуществляется не атомарно, поэтому во
(int и long), которые могут выполняться атомарно. Для этого предусмотре-         время постепенного внесения изменений объект кратковременно пребы-
ны четыре статических метода класса System.Threading.Interlocked, а имен-        вает в некорректном состоянии – при этом должен быть исключен
но Increment, Decrement, Exchange и CompareExchange. Применение этих мето-       не только доступ других потоков, пытающихся внести изменения, но даже
дов аналогично соответствующим Interlocked... процедурам Win32 API.              потоков, осуществляющих чтение.
     Возвращаясь к примеру использования потоков для умножения мат-                   Мониторы
риц, можно выделить один момент, требующий исправления: самое нача-                   Мониторы в .NET являются аналогами критических секций в Win32
ло процедуры потока, там, где определяется номер полосы:                         API. Использование мониторов достаточно эффективно (это один из са-
                                                                                 мых эффективных механизмов) и удобно настолько, что в .NET был пре-
      public static void ThreadProc()                                            дусмотрен механизм, который позволяет использовать практически лю-
      {                                                                          бой объект, хранящийся в управляемой куче, для синхронизации доступа.