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

UptoLike

for ( k = from; k < to; k++ )
m_C[i,j] += m_A[i,k] * m_B[k,j];
}
}
}
public static void Main()
{
Thread[] T = new Thread[ m_stripmax ];
int i,j,errs;
for ( i = 0; i < m_size; i++ ) {
for ( j = 0; j < m_size; j++ ) {
m_A[i,j] = m_B[i,j] = 1.0;
m_C[i,j] = 0.0;
}
}
for ( i = 0; i < m_stripmax; i++ ) {
T[i] = new Thread(new ThreadStart(ThreadProc));
T[i].Start();
}
// дожидаемся завершения всех потоков
for ( i = 0; i < m_stripmax; i++ ) T[i].Join();
// проверяем результат
errs = 0;
for ( i = 0; i < m_size; i++ )
for ( j = 0; j < m_size; j++ )
if ( m_C[i,j] != m_size ) errs++;
Console.WriteLine(“Error count = {0}”, errs );
}
}
}
Поток в .NET может находиться в одном из следующих состояний:
незапущенном, исполнения, ожидания, приостановленном, завершенном
и прерванном. Возможные переходы между этими состояниями изобра-
жены на рис. 7.1.
Сразу после создания и до начала выполнения потока он находится в
незапущенном состоянии (Unstarted). Текущее состояние можно опреде-
лить с помощью свойства Thread.ThreadState. После запуска поток можно
перевести в состояние исполнения (Running) вызовом метода Thread.Start.
Работающий поток может быть переведен в состояние ожидания
(WaitSleepJoin) явным или неявным вызовом соответствующих методов
(Thread.Sleep, Thread.Join и др.) или приостановлен (Suspended) с помощью
метода Thread.Suspend(). Исполнение приостановленного потока можно
Разработка параллельных приложений для ОС Windows
253
Основные классы для реализации многопоточных приложений опре-
делены в пространстве имен System.Threading. Для описания собственных
потоков предназначен класс Thread. При создании потока ему необходимо
указать делегата, реализующего процедуру потока. К сожалению, в .NET,
во-первых, не предусмотрено передачи аргументов в эту процедуру, во-
вторых, процедура должна быть статическим методом, и в-третьих, класс
Thread является опечатанным. В результате передача каких-либо данных в
процедуру потока вызывает определенные трудности и требует явного или
косвенного использования статических полей, что не слишком удобно,
зачастую нуждается в дополнительной синхронизации и плохо соответст-
вует парадигме ООП.
Приведенный ниже пример демонстрирует работу с созданием
нескольких потоков для параллельного перемножения двух квадратных
матриц. Начальные значения всех элементов матриц равны 1, поэтому ре-
зультирующая матрица должна быть заполнена числами, равными размер-
ности перемножаемых матриц. В процессе умножения и суммирования
элементов матриц синхронизация не выполняется, поэтому при достаточ-
но большом размере матриц гарантированно будут возникать ошибки (не-
обходимо синхронизировать выполнение некоторых действий в потоках,
чтобы избежать возникновения ошибок, – об этом ниже, при рассмотре-
нии средств синхронизации):
using System;
using System.Threading;
namespace TestNamespace {
class TestApp {
const int m_size = 600;
const int m_stripsize = 50;
const int m_stipmax = 12;
private static int m_stripused = 0;
private static double[,] m_A = new double[m_size,m_size],
m_B = new double[m_size,m_size],
m_C = new double[m_size,m_size];
public static void ThreadProc()
{
int i,j,k, from, to;
from = ( m_stripused++ ) * m_stripsize;
to = from + m_stripsize;
if ( to > m_size ) to = m_size;
for ( i = 0; i < m_size; i++ ) {
for ( j = 0; j < m_size; j++ ) {
252
CIL и системное программирование в Microsoft .NET
252                         CIL и системное программирование в Microsoft .NET   Разработка параллельных приложений для ОС Windows                    253


     Основные классы для реализации многопоточных приложений опре-                                  for ( k = from; k < to; k++ )
делены в пространстве имен System.Threading. Для описания собственных                                 m_C[i,j] += m_A[i,k] * m_B[k,j];
потоков предназначен класс Thread. При создании потока ему необходимо                           }
указать делегата, реализующего процедуру потока. К сожалению, в .NET,                       }
во-первых, не предусмотрено передачи аргументов в эту процедуру, во-                     }
вторых, процедура должна быть статическим методом, и в-третьих, класс                    public static void Main()
Thread является опечатанным. В результате передача каких-либо данных в                   {
процедуру потока вызывает определенные трудности и требует явного или                      Thread[] T = new Thread[ m_stripmax ];
косвенного использования статических полей, что не слишком удобно,                         int      i,j,errs;
зачастую нуждается в дополнительной синхронизации и плохо соответст-                       for ( i = 0; i < m_size; i++ ) {
вует парадигме ООП.                                                                           for ( j = 0; j < m_size; j++ ) {
     Приведенный ниже пример демонстрирует работу с созданием                                    m_A[i,j] = m_B[i,j] = 1.0;
нескольких потоков для параллельного перемножения двух квадратных                                m_C[i,j] = 0.0;
матриц. Начальные значения всех элементов матриц равны 1, поэтому ре-                         }
зультирующая матрица должна быть заполнена числами, равными размер-                        }
ности перемножаемых матриц. В процессе умножения и суммирования                            for ( i = 0; i < m_stripmax; i++ ) {
элементов матриц синхронизация не выполняется, поэтому при достаточ-                          T[i] = new Thread(new ThreadStart(ThreadProc));
но большом размере матриц гарантированно будут возникать ошибки (не-                          T[i].Start();
обходимо синхронизировать выполнение некоторых действий в потоках,                         }
чтобы избежать возникновения ошибок, – об этом ниже, при рассмотре-                        // дожидаемся завершения всех потоков
нии средств синхронизации):                                                                for ( i = 0; i < m_stripmax; i++ ) T[i].Join();
                                                                                           // проверяем результат
      using System;                                                                         errs = 0;
      using System.Threading;                                                               for ( i = 0; i < m_size; i++ )
                                                                                                for ( j = 0; j < m_size; j++ )
      namespace TestNamespace {                                                                    if ( m_C[i,j] != m_size ) errs++;
        class TestApp {                                                                     Console.WriteLine(“Error count = {0}”, errs );
          const int                   m_size = 600;                                      }
          const int                   m_stripsize = 50;                                 }
          const int                   m_stipmax = 12;                                }
          private static int          m_stripused = 0;                               Поток в .NET может находиться в одном из следующих состояний:
          private static double[,]    m_A = new double[m_size,m_size],          незапущенном, исполнения, ожидания, приостановленном, завершенном
                                      m_B = new double[m_size,m_size],          и прерванном. Возможные переходы между этими состояниями изобра-
                                      m_C = new double[m_size,m_size];          жены на рис. 7.1.
          public static void ThreadProc()                                            Сразу после создания и до начала выполнения потока он находится в
          {                                                                     незапущенном состоянии (Unstarted). Текущее состояние можно опреде-
            int i,j,k, from, to;                                                лить с помощью свойства Thread.ThreadState. После запуска поток можно
            from = ( m_stripused++ ) * m_stripsize;                             перевести в состояние исполнения (Running) вызовом метода Thread.Start.
            to = from + m_stripsize;                                            Работающий поток может быть переведен в состояние ожидания
            if ( to > m_size ) to = m_size;                                     (WaitSleepJoin) явным или неявным вызовом соответствующих методов
            for ( i = 0; i < m_size; i++ ) {                                    (Thread.Sleep, Thread.Join и др.) или приостановлен (Suspended) с помощью
              for ( j = 0; j < m_size; j++ ) {                                  метода Thread.Suspend(). Исполнение приостановленного потока можно