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

UptoLike

или не изменять состояние ожидаемого объекта. Так, например, для собы-
тий с ручным сбросом (ManualResetEvent) состояние не меняется, а собы-
тия с автоматическим сбросом и мьютексы (AutoResetEvent, Mutex) пере-
водятся в занятое состояние.
Объекты класса WaitHandle и производных от него, представляя объ-
екты ядра операционной системы, могут быть использованы для межпро-
цессного взаимодействия. Конструкторы производных объектов (событий
и мьютексов) позволяют задать имя объекта ядра, предназначенное для
организации общего доступа к объектам процессами:
using System;
using System.Threading;
namespace TestNamespace {
public class SomeData {
public const int m_queries = 10;
private static int m_counter = 0;
private static Mutex m_mutex = new Mutex();
private static ManualResetEvent m_event =
new ManualResetEvent( false );
public static void Invoke( int no ) {
m_mutex.WaitOne();
m_counter++;
if ( m_counter >= m_queries ) m_event.Set();
m_mutex.ReleaseMutex();
m_event.WaitOne();
}
}
public delegate void AsyncProcCallback( int no );
class TestApp {
public static void Main() {
int i;
WaitHandle[] wh;
AsyncProcCallback apd;
wh = new WaitHandle[ SomeData.m_queries ];
apd = new AsyncProcCallback( SomeData.Invoke );
for ( i = 0; i < SomeData.m_queries; i++ ) wh[i] =
apd.BeginInvoke(i,null,null).AsyncWaitHandle;
WaitHandle.WaitAll( wh );
}
}
}
Разработка параллельных приложений для ОС Windows
267
if ( to > m_size ) to = m_size;
for ( i = 0; i < m_size; i++ ) {
for ( j = 0; j < m_size; j++ ) {
R = 0;
for ( k = from; k < to; k++ ) R += m_A[i,k]*m_B[k,j];
lock ( m_C ) { m_C[i,j] += R; }
}
}
}
Данный пример показывает процедуру потока, осуществляющего по-
полосное умножение матриц с необходимой синхронизацией. Следует за-
метить, что синхронизация доступа требует дополнительных ресурсов
процессора (в данном случае, качественно превышающих затраты на ум-
ножение и сложение двух чисел с плавающей запятой), поэтому целесооб-
разно как можно сильнее сократить число блокировок и время их наложе-
ния. В примере для этого использована промежуточная переменная R, на-
капливающая частичный результат.
Следует особо подчеркнуть, что мониторы и блокировки доступа
только лишь позволяют разработчику реализовать соответствующую син-
хронизацию, но ни в коем случае не осуществляют принудительное огра-
ничение конкурентного обращения к полям и методам объектов. Любой
параллельно выполняющийся фрагмент кода сохраняет полную возмож-
ность обращаться со всеми объектами, независимо от того, связаны они с
какими-либо блокировками или нет. Для синхронизации и блокирования
доступа необходимо, чтобы все участники синхронизации явным образом
использовали критические секции.
Ожидающие объекты
.NET предоставляет базовый класс WaitHandle, служащий для описа-
ния объекта, который находится в одном из двух состояний: занятом или
свободном. На основе этого класса строятся другие классы синхронизиру-
ющих объектов .NET, такие как события (ManualResetEvent и
AutoResetEvent) и мьютексы (Mutex).
Класс WaitHandle является, по сути, оберткой объектов ядра операци-
онной системы, поддерживающих интерфейс синхронизации. Свойство
Handle объекта WaitHandle позволяет установить (или узнать) соответствие
этого объекта .NET с объектом ядра операционной системы.
Существует три метода класса WaitHandle для ожидания освобожде-
ния объекта: метод WaitOne, являющийся методом объекта, и статические
методы WaitAny и WaitAll. Метод WaitOne является оберткой вызова
WaitForSingleObject Win32 API, а методы WaitAny и WaitAll – вызова
WaitForMultipleObjects. Соответственно семантике конкретных объектов
ядра, представленных объектом WaitHandle, методы Wait...могут изменять
266
CIL и системное программирование в Microsoft .NET
266                         CIL и системное программирование в Microsoft .NET   Разработка параллельных приложений для ОС Windows                  267


       if ( to > m_size ) to = m_size;                                          или не изменять состояние ожидаемого объекта. Так, например, для собы-
       for ( i = 0; i < m_size; i++ ) {                                         тий с ручным сбросом (ManualResetEvent) состояние не меняется, а собы-
         for ( j = 0; j < m_size; j++ ) {                                       тия с автоматическим сбросом и мьютексы (AutoResetEvent, Mutex) пере-
           R = 0;                                                               водятся в занятое состояние.
           for ( k = from; k < to; k++ ) R += m_A[i,k]*m_B[k,j];                     Объекты класса WaitHandle и производных от него, представляя объ-
           lock ( m_C ) { m_C[i,j] += R; }                                      екты ядра операционной системы, могут быть использованы для межпро-
         }                                                                      цессного взаимодействия. Конструкторы производных объектов (событий
       }                                                                        и мьютексов) позволяют задать имя объекта ядра, предназначенное для
     }                                                                          организации общего доступа к объектам процессами:
     Данный пример показывает процедуру потока, осуществляющего по-
полосное умножение матриц с необходимой синхронизацией. Следует за-                  using System;
метить, что синхронизация доступа требует дополнительных ресурсов                    using System.Threading;
процессора (в данном случае, качественно превышающих затраты на ум-
ножение и сложение двух чисел с плавающей запятой), поэтому целесооб-                namespace TestNamespace {
разно как можно сильнее сократить число блокировок и время их наложе-                  public class SomeData {
ния. В примере для этого использована промежуточная переменная R, на-                    public const int           m_queries = 10;
капливающая частичный результат.                                                         private static int         m_counter = 0;
     Следует особо подчеркнуть, что мониторы и блокировки доступа                        private static Mutex       m_mutex = new Mutex();
только лишь позволяют разработчику реализовать соответствующую син-                      private static ManualResetEvent m_event =
хронизацию, но ни в коем случае не осуществляют принудительное огра-                                   new ManualResetEvent( false );
ничение конкурентного обращения к полям и методам объектов. Любой                        public static void Invoke( int no ) {
параллельно выполняющийся фрагмент кода сохраняет полную возмож-                            m_mutex.WaitOne();
ность обращаться со всеми объектами, независимо от того, связаны они с                      m_counter++;
какими-либо блокировками или нет. Для синхронизации и блокирования                          if ( m_counter >= m_queries ) m_event.Set();
доступа необходимо, чтобы все участники синхронизации явным образом                         m_mutex.ReleaseMutex();
использовали критические секции.                                                            m_event.WaitOne();
     Ожидающие объекты                                                                   }
     .NET предоставляет базовый класс WaitHandle, служащий для описа-                  }
ния объекта, который находится в одном из двух состояний: занятом или                  public delegate void AsyncProcCallback( int no );
свободном. На основе этого класса строятся другие классы синхронизиру-                 class TestApp {
ющих объектов .NET, такие как события (ManualResetEvent и                                public static void Main() {
AutoResetEvent) и мьютексы (Mutex).                                                         int                i;
     Класс WaitHandle является, по сути, оберткой объектов ядра операци-                    WaitHandle[]       wh;
онной системы, поддерживающих интерфейс синхронизации. Свойство                             AsyncProcCallback apd;
Handle объекта WaitHandle позволяет установить (или узнать) соответствие                    wh = new WaitHandle[ SomeData.m_queries ];
этого объекта .NET с объектом ядра операционной системы.                                   apd = new AsyncProcCallback( SomeData.Invoke );
     Существует три метода класса WaitHandle для ожидания освобожде-                        for ( i = 0; i < SomeData.m_queries; i++ ) wh[i] =
ния объекта: метод WaitOne, являющийся методом объекта, и статические                          apd.BeginInvoke(i,null,null).AsyncWaitHandle;
методы WaitAny и WaitAll. Метод WaitOne является оберткой вызова                            WaitHandle.WaitAll( wh );
WaitForSingleObject Win32 API, а методы WaitAny и WaitAll – вызова                       }
WaitForMultipleObjects. Соответственно семантике конкретных объектов                   }
ядра, представленных объектом WaitHandle, методы Wait...могут изменять               }