Net, створення вторинних потоків
При програмному створенні додаткових потоків для виконання деякої одиниці роботи необхідно слідувати строго регламентованому процесу:
Створити метод, який буде точкою входу для нового потоку.
Створити об'єкт Thread, передавши в якості аргументу конструктора ParametrizedThreadStart / ThreadStart.
Встановити початкові характеристики потоку (ім'я, пріоритет і т.п.).
Викликати метод Thread.Start (). Це запустить потік на методі, який вказаний делегатом, створеним на другому кроці, як тільки це буде можливо.
Відповідно до другого кроку, можна використовувати два різних типи делегатів для "вказівки" методу, який виконає вторинний потік. Делегат ThreadStart відноситься до простору імен System.Threading, починаючи з .NET 1.0, і він може вказувати на будь-який метод, що не приймає аргументів і нічого не повертає. Цей делегат знадобиться, коли метод призначений просто для запуску у фоновому режимі, без будь-якого подальшого взаємодії.
Очевидне обмеження ThreadStart пов'язано з неможливість передавати йому параметри для обробки. Проте, тип делегата ParametrizedThreadStart дозволяє передати єдиний параметр типу System.Object. З огляду на, що за допомогою System.Object представляється все, що завгодно, можна передати будь-яку кількість параметрів через спеціальний клас або структуру. Однак майте на увазі, що делегат ParametrizedThreadStart може вказувати тільки на методи, які повертають void.
делегат ThreadStart
Щоб проілюструвати процес побудови многопоточного додатки (а також його користь), припустимо, що є консольний додаток, яке дозволяє кінцевому користувачеві вибирати, буде додаток виконувати свою роботу в єдиному первинному потоці або розподілить робоче навантаження на два окремих потоку виконання.
Після імпортування простору імен System.Threading наступний крок полягає у визначенні методу для виконання роботи (можливого) вторинного потоку. Щоб зосередитися на механізмі побудови багатопоточних програм, цей метод буде просто виводити на консоль послідовність чисел, зупиняючись приблизно на 2 секунди на кожному кроці. Нижче показано повне визначення класу:
Усередині Main () спочатку користувачеві пропонується вирішити, скільки потоків застосовувати для виконання роботи програми: один або два. Якщо користувач запитує один потік, потрібно просто викликати метод ThreadNumbers () всередині первинного потоку. Якщо ж користувач віддає перевагу двом потокам, необхідно створити делегат ThreadStart, який вказує на ThreadNumbers (), передати об'єкт делегата конструктору нового об'єкта Thread і викликати метод Start (), інформуючи середу CLR, що цей потік готовий до обробки.
Якщо тепер запустити цю програму в одному потоці, виявиться, що фінальне вікно повідомлення не відображає повідомлення, поки вся послідовність чисел не буде виведена на консоль. Оскільки після виведення кожного числа встановлена пауза приблизно в 2 секунди, це створить не дуже приємне враження у користувача. Однак в разі вибору двох потоків вікно повідомлення відображається негайно, оскільки для виведення чисел на консоль виділений окремий унікальний об'єкт Thread:

Найчастіше в багатопотокової програмі потрібно, щоб основний потік був останнім потоком, завершальним її виконання. Формально програма продовжує виконуватися до тих пір, поки не завершаться всі її пріоритетні потоки. Тому вимагати, щоб основний потік завершував виконання програми, зовсім не обов'язково. Проте цього правила прийнято дотримуватися в багатопотоковому програмуванні, оскільки воно явно визначає кінцеву точку програми.
делегат ParametrizedThreadStart
Згадайте, що делегат ThreadStart може вказувати тільки на методи, які повертають void і не мають аргументів. У багатьох випадках це підходить, але якщо потрібно передати дані методу, що виконується у вторинних потоці, то доведеться використовувати тип делегата ParametrizedThreadStart.
Давайте розглянемо приклад:
клас AutoResetEvent
Безпечнішою, хоча також небажаної альтернативою може бути виклик Thread.Sleep () на певний період часу. Проблема в тому, що немає бажання чекати більше, ніж необхідно.
Простий і безпечний до потокам спосіб змусити один потік очікувати завершення іншого потоку, передбачає використання класу AutoResetEvent. У потоці, який повинен чекати (такому як потік методу Main ()), створимо екземпляр цього класу і передамо конструктору false, вказавши, що повідомлення поки не було. У точці, де потрібно очікувати, викличемо метод WaitOne (). Нижче наведено змінений клас Program, який робить все це, використовуючи статичну змінну-член AutoResetEvent: