Синхронизация с помощью ключевого слова lock в C#
Синхронизация с помощью ключевого слова lock в C#
Первой из возможностей, которую вы можете применить в C# для синхронизации доступа к совместно используемым ресурсам, является использование ключевого слова lock. Это ключевое слово позволяет определить контекст операторов, которые должны синхронизироваться между потоками. В результате входящие потоки не смогут прервать текущий поток, пока он выполняет свою работу. Ключевое слово lock требует, чтобы вы указали маркер (объектную ссылку), который потребуется потоку для входа в пределы контекста lock. При блокировке метода уровня экземпляра можно использовать просто ссылку на текущий тип.
// Использование текущего объекта в качестве маркера потока.
lock(this) {
// Весь программный код в этом контексте оказывается
// устойчивым в отношении потоков.
}
При внимательном изучении метода PrintNumbers() становится ясно, что совместно используемым ресурсом, за доступ к которому соперничают потоки, является окно консоли. Поместите в рамки соответствующего контекста блокировки все операторы взаимодействии с типом Console так, как показано ниже.
public void PrintNumbers() {
lock (this) {
// Вывод информации Thread.
Console.WriteLine("-› {0} выполняет PrintNumbers()", Thread.CurrentThread.Name);
// Вывод чисел.
Console.Write("Ваши числа": ");
for (int i = 0; i ‹ 10; i++) {
Random r = new Random();
Thread.Sleep(1000 * r.Next(5));
Console.Write(i + ", ");
}
Console.WriteLine();
}
}
Тем самым вы создадите метод, который позволит текущему потоку завершить выполнение своей задачи. Как только поток вступит в контекст блокировки, соответствующий маркер блокировки (в данном случае эта ссылка на текущий объект) станет недоступным другим потокам, пока блокировка не будет снята в результате выхода потока из контекста блокировки. Например, если маркер блокировки получает поток А, то другие потоки не смогут войти в контекст до тех пор, пока поток А не освободит маркер блокировки.
Замечание. Если пытаться блокировать программный код в статическом методе, вы, очевидно, не можете использовать ключевое слово this. Но в этом случае можно передать объект System.Type соответствующего класса с помощью оператора C# typeof.
Если снова выполнить это приложение, вы увидите, что теперь каждый поток получает возможность закончить свою работу (рис. 14.10).
Рис. 14.10. Конкуренция в действии, третья попытка
Исходный код. Проект MultiThreadedPrinting размещен в подкаталоге, соответствующем главе 14.