C# 4.0 полное руководство - 2011
Шрифт:
Поток с низким приоритетом завершен.
Поток с высоким приоритетом досчитал до 1000000000 Поток с низким приоритетом досчитал до 23996334
Судя по результату, высокоприоритетный поток получил около 98% всего времени, которое было выделено для выполнения этой программы. Разумеется, конкретный результат может отличаться в зависимости от быстродействия ЦП и числа других задач, решаемых в системе, а также от используемой версии Windows.
Многопоточный код может вести себя по-разному в различных средах, поэтому никогда не следует полагаться
Синхронизация
Когда используется несколько потоков, то иногда приходится координировать действия двух или более потоков. Процесс достижения такой координации называется синхронизацией. Самой распространенной причиной применения синхронизации служит необходимость разделять среди двух или более потоков общий ресурс, который может быть одновременно доступен только одному потоку. Например, когда в одном потоке выполняется запись информации в файл, второму потоку должно быть запрещено делать это в тот же самый момент времени. Синхронизация требуется и в том случае, если один поток ожидает событие, вызываемое другим потоком. В подобной ситуации требуются какие-то средства, позволяющие приостановить один из потоков до тех пор, пока не произойдет событие в другом потоке. После этого ожидающий поток может возобновить свое выполнение.
В основу синхронизации положено понятие блокировки, посредством которой организуется управление доступом к кодовому блоку в объекте. Когда объект заблокирован одним потоком, остальные потоки не могут получить доступ к заблокированному кодовому блоку. Когда же блокировка снимается одним потоком, объект становится доступным для использования в другом потоке.
Средство блокировки встроено в язык С#. Благодаря этому все объекты могут быть синхронизированы. Синхронизация организуется с помощью ключевого слова lock. Она была предусмотрена в C# с самого начала, и поэтому пользоваться ею намного проще, чем кажется на первый взгляд. В действительности синхронизация объектов во многих программах на C# происходит практически незаметно.
Ниже приведена общая форма блокировки:
lock(lockObj) {
// синхронизируемые операторы
}
где lockObj обозначает ссылку на синхронизируемый объект. Если же требуется синхронизировать только один оператор, то фигурные скобки не нужны. Оператор lock гарантирует, что фрагмент кода, защищенный блокировкой для данного объекта, будет использоваться только в потоке, получающем эту блокировку. А все остальные потоки блокируются до тех пор, пока блокировка не будет снята. Блокировка снимается по завершении защищаемого ею фрагмента кода.
Блокируемым
В приведенной ниже программе синхронизация демонстрируется на примере управления доступом к методу Sumlt , суммирующему элементы целочисленного массива.
// Использовать блокировку для синхронизации доступа к объекту.
using System;
using System.Threading;
class SumArray { int sum;
object lockOn = new object; // закрытый объект, доступный
// для последующей блокировки
lock(lockOn) { // заблокировать весь метод
sum =0; // установить исходное значение суммы
for(int i=0; i < nums.Length; i++) {
sum +- nums[i];
Console.WriteLine("Текущая сумма для потока " +
Thread.CurrentThread.Name + " равна " + sum); Thread.Sleep(10); // разрешить переключение задач
}
return sum;
}
}
}
class MyThread {
public Thread Thrd; int[] a; int answer;
// Создать один объект типа SumArray для всех // экземпляров класса MyThread. static SumArray sa = new SumArray;
// Сконструировать новый поток, public MyThread(string name, int [ ] nums) { a = nums;
Thrd = new Thread(this.Run);
Thrd.Name = name;
Thrd.Start; // начать поток
}
// Начать выполнение нового потока, void Run {
Console.WriteLine(Thrd.Name + " начат.");
answer = sa.Sumlt(a);
Console.WriteLine("Сумма для потока " + Thrd.Name + " равна " + answer); Console.WriteLine(Thrd.Name + " завершен.");
}
}
class Sync {
static void Main {