Составители:
Рубрика:
будут создавать и множить свои собственные упакованные представления
типов-значений, и никакой синхронизации не произойдет. Поэтому при
использовании мониторов важно проследить, чтобы вызовы разных мето-
дов в разных потоках использовали один общий объект ссылочного типа.
Можно выделить интересный момент – типы объектов сами являют-
ся экземплярами класса Type, и для них выделяется место в управляемой
куче. Это позволяет использовать тип объекта в качестве владельца запи-
си SyncBlock:
...
for ( j = 0; j < m_size; j++ ) {
for ( k = from; k < to; k++ ) {
Monitor.Enter( typeof(double) );
try {
m_C[i,j] += m_A[i,k] * m_B[k,j];
} finally {
Monitor.Exit( typeof(double) );
}
}
}
...
Возможно неявное использование мониторов в C# с помощью клю-
чевого слова lock:
lock ( obj ) { ... }
эквивалентна
Monitor.Enter( obj ); try { ... }
finally { Mointor.Exit( obj ); }
Использование ключевого слова lock предпочтительно, так как при
этом выполняется дополнительная синтаксическая проверка – попытка
использовать для блокировки тип-значение приведет к диагностируемой
компилятором ошибке, вместо трудно отлавливаемой ошибки во время
исполнения:
public static void ThreadProc()
{
int i,j,k, from, to;
double R;
from = (Interlocked.Increment(ref m_stripused) – 1) * m_stripsize;
to = from + m_stripsize;
Разработка параллельных приложений для ОС Windows
265
...
for ( j = 0; j < m_size; j++ ) {
for ( k = from; k < to; k++ ) {
Monitor.Enter( m_C );
try {
m_C[i,j] += m_A[i,k] * m_B[k,j];
} finally {
Monitor.Exit( m_C );
}
}
}
...
В этом фрагменте надо выделить два существенных момента: во-пер-
вых, использование метода Exit в блоке finally, а во-вторых – использо-
вание всего массива m_C, а не отдельного элемента m_C[i,j].
Первое надо взять за правило, так как в случае возникновения ис-
ключения в критической секции блокировка может остаться занятой
(т.е. в случае покидания секции без вызова метода Exit).
Второе связано с тем, что элементы m_C[i,j] являются значениями, а
не ссылочными типами. Для типов-значений соответствующее представ-
ление в управляемой куче не создается, и у них нет и не может быть ссы-
лок на синхронизирующие записи SyncBlock.
Самое плохое в этой ситуации то, что попытка собрать приложение,
использующее типы-значения в качестве аргументов методов Enter и Exit
(как в примере ниже), пройдет успешно:
...
for ( j = 0; j < m_size; j++ ) {
for ( k = from; k < to; k++ ) {
Monitor.Enter( m_C[i,j] );
try {
m_C[i,j] += m_A[i,k] * m_B[k,j];
} finally {
Monitor.Exit( m_C[i,j] );
}
}
}
...
В прототипах методов Enter и Exit указано, что они должны получать
ссылочный тип object; соответственно тип-значение будет упакован, и ме-
тоду Enter будет передан свой экземпляр упакованного типа-значения, на
который будет поставлена блокировка, а методу Exit – свой экземпляр, на
котором блокировки никогда не было. Понятно, что все остальные потоки
264
CIL и системное программирование в Microsoft .NET
264 CIL и системное программирование в Microsoft .NET Разработка параллельных приложений для ОС Windows 265 ... будут создавать и множить свои собственные упакованные представления for ( j = 0; j < m_size; j++ ) { типов-значений, и никакой синхронизации не произойдет. Поэтому при for ( k = from; k < to; k++ ) { использовании мониторов важно проследить, чтобы вызовы разных мето- Monitor.Enter( m_C ); дов в разных потоках использовали один общий объект ссылочного типа. try { Можно выделить интересный момент – типы объектов сами являют- m_C[i,j] += m_A[i,k] * m_B[k,j]; ся экземплярами класса Type, и для них выделяется место в управляемой } finally { куче. Это позволяет использовать тип объекта в качестве владельца запи- Monitor.Exit( m_C ); си SyncBlock: } ... } for ( j = 0; j < m_size; j++ ) { } for ( k = from; k < to; k++ ) { ... Monitor.Enter( typeof(double) ); В этом фрагменте надо выделить два существенных момента: во-пер- try { вых, использование метода Exit в блоке finally, а во-вторых – использо- m_C[i,j] += m_A[i,k] * m_B[k,j]; вание всего массива m_C, а не отдельного элемента m_C[i,j]. } finally { Первое надо взять за правило, так как в случае возникновения ис- Monitor.Exit( typeof(double) ); ключения в критической секции блокировка может остаться занятой } (т.е. в случае покидания секции без вызова метода Exit). } Второе связано с тем, что элементы m_C[i,j] являются значениями, а } не ссылочными типами. Для типов-значений соответствующее представ- ... ление в управляемой куче не создается, и у них нет и не может быть ссы- Возможно неявное использование мониторов в C# с помощью клю- лок на синхронизирующие записи SyncBlock. чевого слова lock: Самое плохое в этой ситуации то, что попытка собрать приложение, использующее типы-значения в качестве аргументов методов Enter и Exit lock ( obj ) { ... } (как в примере ниже), пройдет успешно: ... эквивалентна for ( j = 0; j < m_size; j++ ) { for ( k = from; k < to; k++ ) { Monitor.Enter( obj ); try { ... } Monitor.Enter( m_C[i,j] ); finally { Mointor.Exit( obj ); } try { m_C[i,j] += m_A[i,k] * m_B[k,j]; Использование ключевого слова lock предпочтительно, так как при } finally { этом выполняется дополнительная синтаксическая проверка – попытка Monitor.Exit( m_C[i,j] ); использовать для блокировки тип-значение приведет к диагностируемой } компилятором ошибке, вместо трудно отлавливаемой ошибки во время } исполнения: } ... public static void ThreadProc() В прототипах методов Enter и Exit указано, что они должны получать { ссылочный тип object; соответственно тип-значение будет упакован, и ме- int i,j,k, from, to; тоду Enter будет передан свой экземпляр упакованного типа-значения, на double R; который будет поставлена блокировка, а методу Exit – свой экземпляр, на from = (Interlocked.Increment(ref m_stripused) – 1) * m_stripsize; котором блокировки никогда не было. Понятно, что все остальные потоки to = from + m_stripsize;
Страницы
- « первая
- ‹ предыдущая
- …
- 137
- 138
- 139
- 140
- 141
- …
- следующая ›
- последняя »