Составители:
Рубрика:
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(). Исполнение приостановленного потока можно
Страницы
- « первая
- ‹ предыдущая
- …
- 131
- 132
- 133
- 134
- 135
- …
- следующая ›
- последняя »