Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Инфа.doc
Скачиваний:
12
Добавлен:
04.06.2015
Размер:
766.98 Кб
Скачать
  1. Синхронизация потоков (interlocked-функции и критические секции). Основные проблемы синхронизации.

Выражения lock (C#) и SyncLock (Visual Basic) используются для того, чтобы выполнение блока кода не прерывалось кодом, выполняемым в других потоках.Для этого нужно получить взаимоисключающую блокировку для данного объекта на время длительности блока кода.

Оператор lock или SyncLock получает объект в качестве аргумента, и за ним следует блок кода, который должен выполняться одновременно только в одном потоке.Примеры.

public class TestThreading

{

private System.Object lockThis = new System.Object();

public void Process()

{

lock (lockThis)

{

// Access thread-sensitive resources.

}

}

}

Аргумент, предоставляемый ключевому слову lock, должен быть объектом на основе ссылочного типа; он используется для определения области блокировки.В приведенном выше примере область блокировки ограничена этой функцией, поскольку не существует ссылок на объект lockThis вне функции.Если бы такая ссылка существовала, область блокировки включала бы этот объект.Строго говоря, предоставляемый объект используется только для того, чтобы уникальным образом определить ресурс, к которому предоставляется доступ для различных потоков, поэтому это может быть произвольный экземпляр класса.В действительности этот объект обычно представляет ресурс, для которого требуется синхронизация потоков.Например, если объект контейнера должен использоваться в нескольких потоках, то контейнер можно передать блокировке, а блок синхронизированного кода после блокировки должен получить доступ к контейнеру.Если другие потоки блокируются для того же контейнера перед доступом к нему, обеспечивается безопасная синхронизация доступа к объекту.

Как правило, рекомендуется избегать блокировки типа public или экземпляров объектов, которыми не управляет код вашего приложения.Например, использование lock(this) может привести к неполадкам, если к экземпляру разрешен открытый доступ, поскольку внешний код также может блокировать объект.Это может привести к созданию ситуаций взаимной блокировки, когда два или несколько потоков будут ожидать высвобождения одного и того же объекта.По этой же причине блокировка открытого типа данных (в отличие от объектов) может привести к неполадкам.Блокировка строковых литералов наиболее опасна, поскольку строковые литералы интернируются средой CLR.Это означает, что если во всей программе есть один экземпляр любого строкового литерала, точно такой же объект будет представлять литерал во всех запущенных доменах приложения и во всех потоках.В результате блокировка, включенная для строки с одинаковым содержимым во всем приложении, блокирует все экземпляры этой строки в приложении.По этой причине лучше использовать блокировку закрытых или защищенных членов, для которых интернирование не применяется.В некоторых классах есть члены, специально предназначенные для блокировки.Например, в типе Array есть SyncRoot.Во многих типах коллекций есть член SyncRoot.

Как и ключевые слова lock и SyncLock, мониторы не допускают одновременное выполнение несколькими потоками одних и тех не блоков кода.Метод Enterпозволяет только одному методу переходить к последующим операторам, все прочие методы заблокированы, пока выполняемый метод не вызоветExit.Это аналогично использованию ключевого слова lock.

System.Object obj = (System.Object)x;

System.Threading.Monitor.Enter(obj);

try

{

DoSomething();

}

finally

{

System.Threading.Monitor.Exit(obj);

}

Мьютекс аналогичен монитору, он не допускает одновременного выполнения блока кода более чем из одного потока.Название "мьютекс" – сокращенная форма слова "взаимоисключающий" ("mutually exclusive" на английском языке). Впрочем, в отличие от мониторов мьютексы можно использовать для синхронизации потоков по процессам.Мьютекс представляется классом Mutex.

Методы класса Interlocked можно использовать для предотвращения проблем, возникающих при одновременной попытке нескольких потоков обновить или сравнить некоторое значение.Методы этого класса позволяют безопасно увеличивать, уменьшать, заменять и сравнивать значения переменных из любого потока.

Предоставляет атомарные операции для переменных, общедоступных нескольким потокам.

Тип Interlocked предоставляет следующие члены.

Add(Int32, Int32) Добавляет два 32-битных целых числа и заменяет первое число на сумму (атомарная операция). CompareExchange(Double, Double, Double) Сравнивает два числа с плавающей запятой с двойной точностью на ет два числа с плавающей запятой с обычной точностью на равенство и, если они равны, заменяет одно из значений. CompareExchange<T>(T, T, T) Сравнивает два экземпляра указанного ссылочного типа T на равенство и, если это так, заменяет один из них.

Decrement(Int32) Уменьшает значение заданной переменной и сохраняет результат — как атомарная операция. Exchange<T>(T, T) Задает переменную указанного типа T в значение и возвращает исходное значение (атомарная операция).

Increment(Int) Увеличивает значение заданной переменной и сохраняет результат — как атомарная операция.

Read

static bool UseResource()

{

//0 indicates that the method is not in use.

if(0 == Interlocked.Exchange(ref usingResource, 1))

{

Console.WriteLine("{0} acquired the lock", Thread.CurrentThread.Name);

//Code to access a resource that is not thread safe would go here.

//Simulate some work

Thread.Sleep(500);

Console.WriteLine("{0} exiting lock", Thread.CurrentThread.Name);

//Release the lock

Interlocked.Exchange(ref usingResource, 0);

return true;

}

  1. Способы передачи параметров вызова. Передача по значению и по ссылке, их различия и варианты применения.

В C# параметры могут быть переданы либо по значению, либо по ссылке. Передача параметров по ссылке позволяет изменять и сохранять измененные значения параметров членов функций, методов, свойств, индексаторов, операторов и конструкторов. Для передачи параметра по ссылке используйте ключевое слово ref или out. Для простоты в этом примере используется только ключевое слово ref. Дополнительные сведения об отличиях ключевых словref и out (out может быть непроинициализирован при передаче по ссылке)

static void Square(int x)

{

// code...

}

static void Square(ref int x)

{

// code...

}