Передача аргумента потоку

Первоначально в среде .NET Framework нельзя было передавать аргумент потоку, когда он начинался, поскольку у метода, служившего в качестве точки входа в поток, не могло быть параметров. Если же потоку требовалось передать какую-то информацию, то к этой цели приходилось идти различными обходными путями, например использовать общую переменную. Но этот недостаток был впоследствии устранен, и теперь аргумент может быть передан потоку. Для этого придется воспользоваться другими формами метода Start(), конструктора класса Thread, а также метода, служащего в качестве точки входа в поток.

Аргумент передается потоку в следующей форме метода Start().

public void Start(object параметр)

Объект, указываемый в качестве аргумента параметр, автоматически передается методу, выполняющему роль точки входа в поток. Следовательно, для того чтобы передать аргумент потоку, достаточно передать его методу Start().

Для применения параметризированной формы метода Start() потребуется следующая форма конструктора класса Thread:

public Thread(ParameterizedThreadStart запуск)

где запуск обозначает метод, вызываемый с целью начать выполнение потока. Обратите внимание на то, что в этой форме конструктора запуск имеет тип ParameterizedThreadStart, а не ThreadStart, как в форме, использовавшейся в предыдущих примерах. В данном случае ParameterizedThreadStart является делегатом, объявляемым следующим образом.

public delegate void ParameterizedThreadStart(object obj)

Как видите, этот делегат принимает аргумент типа object. Поэтому для правильного применения данной формы конструктора класса Thread у метода, служащего в качестве точки входа в поток, должен быть параметр типа object.

В приведенном ниже примере программы демонстрируется передача аргумента потоку.

// Пример передачи аргумента методу потока.

using System;

using System.Threading;

class MyThread {

  public int Count;

  public Thread Thrd;

  // Обратите внимание на то, что конструктору класса

  // MyThread передается также значение типа int.

  public MyThread(string name, int num) {

    Count = 0;

    // Вызвать конструктор типа ParameterizedThreadStart

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

    Thrd = new Thread(this.Run);

    Thrd.Name = name;

    // Здесь переменная num передается методу Start()

    // в качестве аргумента.

    Thrd.Start(num);

  }

  // Обратите внимание на то, что в этой форме метода Run()

  // указывается параметр типа object.

  void Run(object num) {

    Console.WriteLine(Thrd.Name + " начат со счета " + num);

    do {

      Thread.Sleep (500);

      Console.WriteLine("В потоке " + Thrd.Name +

               ", Count = " + Count);

      Count++;

    } while(Count < (int) num);

    Console.WriteLine(Thrd.Name + " завершен.");

  }

}

class PassArgDemo {

  static void Main() {

    // Обратите внимание на то, что число повторений

    // передается этим двум объектам типа MyThread.

    MyThread mt = new MyThread("Потомок #1", 5);

    MyThread mt2 = new MyThread("Потомок #2", 3);

    do {

      Thread.Sleep(100);

    } while (mt.Thrd.IsAlive ||

             mt2.Thrd.IsAlive);

    Console.WriteLine("Основной поток завершен.");

  }

}

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

Потомок #1 начат со счета 5

Потомок #2 начат со счета 3

В потоке Потомок #1, Count = 0

В потоке Потомок #2, Count = 0

В потоке Потомок #1, Count = 1

В потоке Потомок #2, Count = 1

В потоке Потомок #1, Count = 2

В потоке Потомок #2, Count = 2

Потомок #2 завершен.

В потоке Потомок #1, Count = 3

В потоке Потомок #1, Count = 4

Потомок #1 завершен.

Основной поток завершен.

Как следует из приведенного выше результата, первый поток повторяется пять раз, а второй — три раза. Число повторений указывается в конструкторе класса MyThread и затем передается методу Run(), служащему в качестве точки входа в поток, с помощью параметризированной формы ParameterizedThreadStart метода Start().