Читать книги » Книги » Компьютеры и Интернет » Программирование » Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен

Читать книгу Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен, Эндрю Троелсен . Жанр: Программирование.
Язык программирования C#9 и платформа .NET5 - Эндрю Троелсен
Название: Язык программирования C#9 и платформа .NET5
Дата добавления: 26 август 2023
Количество просмотров: 565
(18+) Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту для удаления материала.
Читать онлайн

Язык программирования C#9 и платформа .NET5 читать книгу онлайн

Язык программирования C#9 и платформа .NET5 - читать онлайн , автор Эндрю Троелсен

В 10-м издании книги описаны новейшие возможности языка C# 9 и .NET 5 вместе с подробным "закулисным" обсуждением, призванным расширить навыки критического мышления разработчиков, когда речь идет об их ремесле.
Книга охватывает ASP.NET Core, Entity Framework Core и многое другое наряду с последними обновлениями унифицированной платформы .NET, начиная с улучшений показателей производительности настольных приложений Windows в .NET 5 и обновления инструментария XAML и заканчивая расширенным рассмотрением файлов данных и способов обработки данных.
Все примеры кода были переписаны с учетом возможностей последнего выпуска C# 9.

Перейти на страницу:
проблемы. В то время как каждый поток сообщает экземпляру Printer о необходимости вывода числовых данных, планировщик потоков благополучно переключает потоки в фоновом режиме. В итоге получается несогласованный вывод. Нужен способ программной реализации синхронизированного доступа к разделяемым ресурсам. Как и можно было предположить, пространство имен System.Threading предлагает несколько типов, связанных с синхронизацией. В языке C# также предусмотрено ключевое слово для синхронизации разделяемых данных в многопоточных приложениях.

Синхронизация с использованием ключевого слова lock языка C#

Первый прием, который можно применять для синхронизации доступа к разделяемым ресурсам, предполагает использование ключевого слова lock языка С#. Оно позволяет определять блок операторов, которые должны быть синхронизованными между потоками. В результате входящие потоки не могут прерывать текущий поток, мешая ему завершить свою работу. Ключевое слово lock требует указания маркера (объектной ссылки), который должен быть получен потоком для входа в область действия блокировки. Чтобы попытаться заблокировать закрытый метод уровня экземпляра, необходимо просто передать ссылку на текущий тип:

private void SomePrivateMethod()

{

  // Использовать текущий объект как маркер потока.

  lock(this)

  {

    // Весь код внутри этого блока является безопасным к потокам.

  }

}

Тем не менее, если блокируется область кода внутри открытого члена, то безопаснее (да и рекомендуется) объявить закрытую переменную-член типа object для применения в качестве маркера блокировки:

public class Printer

{

  // Маркер блокировки.

  private object threadLock = new object();

   public void PrintNumbers()

  {

    // Использовать маркер блокировки.

    lock (threadLock)

    {

      ...

    }

  }

}

В любом случае, если взглянуть на метод PrintNumbers(), то можно заметить, что разделяемым ресурсом, за доступ к которому соперничают потоки, является окно консоли. Поместите весь код взаимодействия с типом Console внутрь области lock, как показано ниже:

public void PrintNumbers()

{

  // Использовать в качестве маркера блокировки закрытый член object.

  lock (threadLock)

  {

    // Вывести информацию о потоке.

    Console.WriteLine("-> {0} is executing PrintNumbers()",

      Thread.CurrentThread.Name);

    // Вывести числа.

    Console.Write("Your numbers: ");

    for (int i = 0; i < 10; i++)

    {

      Random r = new Random();

      Thread.Sleep(1000 * r.Next(5));

      Console.Write("{0}, ", i);

    }

    Console.WriteLine();

  }

}

В итоге вы построили метод, который позволит текущему потоку завершить свою задачу. Как только поток входит в область lock, маркер блокировки (в данном случае ссылка на текущий объект) становится недоступным другим потокам до тех пор, пока блокировка не будет освобождена после выхода из области lock. Таким образом, если поток А получил маркер блокировки, то другие потоки не смогут войти ни в одну из областей, которые используют тот же самый маркер, до тех пор, пока поток А не освободит его.

На заметку! Если необходимо блокировать код в статическом методе, тогда следует просто объявить закрытую статическую переменную-член типа object, которая и будет служить маркером блокировки.

Запустив приложение, вы заметите, что каждый поток получил возможность выполнить свою работу до конца:

*****Synchronizing Threads *****

-> Worker thread #0 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #1 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #3 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #2 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #4 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #5 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #7 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #6 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #8 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

-> Worker thread #9 is executing PrintNumbers()

Your numbers: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,

Синхронизация с использованием типа System.Threading.Monitor

Оператор lock языка C# на самом деле представляет собой сокращение для работы с классом System.Threading.Monitor. При обработке компилятором C# область lock преобразуется в следующую конструкцию (в чем легко убедиться с помощью утилиты ldasm.exe):

public void PrintNumbers()

{

  Monitor.Enter(threadLock);

  try

  {

    // Вывести информацию о потоке.

    Console.WriteLine("-> {0} is executing PrintNumbers()",

      Thread.CurrentThread.Name);

    // Вывести числа.

    Console.Write("Your numbers: ");

    for (int i = 0; i < 10; i++)

    {

      Random r = new Random();

      Thread.Sleep(1000 * r.Next(5));

      Console.Write("{0}, ", i);

    }

    Console.WriteLine();

  }

  finally

  {

    Monitor.Exit(threadLock);

  }

}

Первым делом обратите внимание, что конечным получателем маркера потока, который указывается как аргумент ключевого слова lock, является метод Monitor. Enter(). Весь код внутри области lock помещен внутрь блока try. Соответствующий блок finally гарантирует освобождение маркера блокировки (посредством метода Monitor.Exit()), даже если возникнут любые исключения времени выполнения. Модифицировав программу MultiThreadShareData с целью прямого применения типа Monitor (как только что было показано), вы обнаружите, что вывод идентичен.

С учетом того, что ключевое слово lock требует написания меньшего объема кода, чем при явной работе с типом System.Threading.Monitor, может возникнуть вопрос о преимуществах использования этого типа напрямую.

Перейти на страницу:
Комментарии (0)