Добавить в цитаты Настройки чтения

Страница 404 из 502

<b>               sum);</b>

<b>        Thread.Sleep(10); // разрешить переключение задач</b>

<b>      }</b>

<b>      return sum;</b>

<b>    }</b>

<b>  }</b>

<b>}</b>

<b>class MyThread {</b>

<b>  public Thread Thrd;</b>

<b>  int[] a;</b>

<b>  int answer;</b>

<b>  // Создать один объект типа SumArray для всех</b>

<b>  // экземпляров класса MyThread.</b>

<b>  static SumArray sa = new SumArray();</b>

<b>  // Сконструировать новый поток,</b>

<b>  public MyThread(string name, int [ ] nums) {</b>

<b>    a = nums;</b>

<b>    Thrd = new Thread(this.Run);</b>

<b>    Thrd.Name = name;</b>

<b>    Thrd.Start(); // начать поток</b>

<b>  }</b>

<b>  // Начать выполнение нового потока,</b>

<b>  void Run() {</b>

<b>    Console.WriteLine(Thrd.Name + &quot; начат.&quot;);</b>

<b>    answer = sa.SumIt(a);</b>

<b>    Console.WriteLine(&quot;Сумма для потока &quot; + Thrd.Name +</b>

<b>            &quot; равна &quot; + answer);</b>

<b>    Console.WriteLine(Thrd.Name + &quot; завершен.&quot;);</b>

<b>  }</b>

<b>}</b>

<b>class Sync {</b>

<b>  static void Main() {</b>

<b>    int[] a = {1, 2, 3, 4, 5};</b>

<b>    MyThread mt1 = new MyThread (&quot;Потомок #1&quot;, a);</b>

<b>    MyThread mt2 = new MyThread(&quot;Потомок #2&quot;, a);</b>

<b>    mt1.Thrd.Join();</b>

<b>    mt2.Thrd.Join() ;</b>

<b>  }</b>

<b>}</b>

Ниже приведен результат выполнения данной программы, хотя у вас он может оказаться несколько иным.

<b>Потомок #1 начат.</b>

<b>Потомок #2 начат.</b>

<b>Текущая сумма для потока Потомок #1 равна 1</b>

<b>Текущая сумма для потока Потомок #1 равна 3</b>

<b>Текущая сумма для потока Потомок #1 равна 6</b>

<b>Текущая сумма для потока Потомок #1 равна 10</b>

<b>Текущая сумма для потока Потомок #1 равна 15</b>

<b>Сумма для потока Потомок #1 равна 15</b>

<b>Потомок #1 завершен.</b>

<b>Текущая сумма для потока Потомок #2 равна 1</b>

<b>Текущая сумма для потока Потомок #2 равна 3</b>

<b>Текущая сумма для потока Потомок #2 равна 6</b>

<b>Текущая сумма для потока Потомок #2 равна 10</b>

<b>Текущая сумма для потока Потомок #2 равна 15</b>

<b>Сумма для потока Потомок #2 равна 15</b>

<b>Потомок #2 завершен.</b>

Как следует из приведенного выше результата, в обоих потоках правильно подсчитывается сумма, равная 15.

Рассмотрим эту программу более подробно. Сначала в ней создаются три класса. Первым из них оказывается класс SumArray, в котором определяется метод SumIt(), суммирующий элементы целочисленного массива. Вторым создается класс MyThread, в котором используется статический объект sa типа SumArray. Следовательно, единственный объект типа SumArray используется всеми объектами типа MyThread. С помощью этого объекта получается сумма элементов целочисленного массива. Обратите внимание на то, что текущая сумма запоминается в поле sum объекта типа SumArray. Поэтому если метод SumIt() используется параллельно в двух потоках, то оба потока попытаются обратиться к полю sum, чтобы сохранить в нем текущую сумму. А поскольку это может привести к ошибкам, то доступ к методу SumIt() должен быть синхронизирован. И наконец, в третьем классе, Sync, создаются два потока, в которых подсчитывается сумма элементов целочисленного массива.

Оператор lock в методе SumIt() препятствует одновременному использованию данного метода в разных потоках. Обратите внимание на то, что в операторе lock объект lockOn используется в качестве синхронизируемого. Это закрытый объект, предназначенный исключительно для синхронизации. Метод Sleep() намеренно вызывается для того, чтобы произошло переключение задач, хотя в данном случае это невозможно. Код в методе SumIt() заблокирован, и поэтому он может быть одновременно использован только в одном потоке. Таким образом, когда начинает выполняться второй порожденный поток, он не сможет войти в метод SumIt() до тех пор, пока из него не выйдет первый порожденный поток. Благодаря этому гарантируется получение правильного результата.