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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 280 281 282 283 284 285 286 287 288 ... 642

using System;

using System.Threading;

namespace MultiThreadedPrinting

{

  public class Printer

  {

    public void PrintNumbers()

    {

      // Отобразить информацию о потоке.

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

        Thread.CurrentThread.Name);

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

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

      {

        // Приостановить поток на случайный период времени.

        Random r = new Random();

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

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

      }

      Console.WriteLine();

    }

  }

}

Вызывающий код отвечает за создание массива из десяти (уникально именованных) объектов Thread, каждый из которых вызывает метод одного и того же экземпляра класса Printer:

using System;

using System.Threading;

using MultiThreadedPrinting;

Console.WriteLine("*****Synchronizing Threads *****n");

Printer p = new Printer();

// Создать 10 потоков, которые указывают на один.

// и тот же метод того же самого объекта

Thread[] threads = new Thread[10];

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

{

  threads[i] = new Thread(new ThreadStart(p.PrintNumbers))

  {

    Name = $"Worker thread #{i}"

  };

}

// Теперь запустить их все.

foreach (Thread t in threads)

{

  t.Start();

}

Console.ReadLine();

Прежде чем взглянуть на тестовые запуски, кратко повторим суть проблемы. Первичный поток внутри этого домена приложения начинает свое существование с порождения десяти вторичных рабочих потоков. Каждому рабочему потоку указывается на необходимость вызова метода PrintNumbers() того же самого экземпляра класса Printer. Поскольку никаких мер для блокировки разделяемых ресурсов данного объекта (консоли) не предпринималось, есть неплохой шанс, что текущий поток будет вытеснен до того, как метод PrintNumbers() выведет полные результаты. Из-за того, что не известно в точности, когда подобное может произойти (если вообще произойдет), будут получены непредсказуемые результаты. Например, вывод может выглядеть так:

(window.adrunTag = window.adrunTag || []).push({v: 1, el: 'adrun-4-390', c: 4, b: 390})

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

-> Worker thread #3 is executing PrintNumbers()

-> Worker thread #0 is executing PrintNumbers()

-> Worker thread #1 is executing PrintNumbers()

-> Worker thread #2 is executing PrintNumbers()

-> Worker thread #4 is executing PrintNumbers()

-> Worker thread #5 is executing PrintNumbers()

-> Worker thread #6 is executing PrintNumbers()

-> Worker thread #7 is executing PrintNumbers()

-> Worker thread #8 is executing PrintNumbers()

-> Worker thread #9 is executing PrintNumbers()

0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 2, 3, 1, 2, 2, 2, 1, 2,

1, 1, 2, 2, 3, 3, 4,

3, 3, 2, 2, 3, 4, 3, 4, 5, 4, 5, 4, 4, 3, 6, 7, 2, 3, 4, 4, 4, 5, 6, 5,

3, 5, 8, 9,

6, 7, 4, 5, 6, 6, 5, 5, 5, 8, 5, 6, 7, 8, 7, 7, 6, 6, 6, 8, 9,

8, 7, 7, 7, 7, 9,

6, 8, 9,

8, 9,

9, 9,

8, 8, 7, 8, 9,

9,

9,

Запустите приложение еще несколько раз. Скорее всего, каждый раз вы будете получать отличающийся вывод.

На заметку! Если получить непредсказуемый вывод не удается, увеличьте количество потоков с 10 до 100 (например) или добавьте в код еще один вызов Thread.Sleep(). В конце концов, вы столкнетесь с проблемой параллелизма.

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

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

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

1 ... 280 281 282 283 284 285 286 287 288 ... 642
На этой странице вы можете бесплатно читать книгу Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю бесплатно.
Похожие на Язык программирования C#9 и платформа .NET5 - Троелсен Эндрю книги

Оставить комментарий