TGViewer
Библиотека шарписта | C#, F#, .NET, ASP.NET Библиотека шарписта | C#, F#, .NET, ASP.NET @csharpproglib · 21.7K subscribers
Post #7079 2.5K
🔍 Thread.Start в C# — что происходит после вызова

Thread.Start существует с первой версии .NET, и большинство разработчиков знают, что он «запускает поток». Но что именно происходит в момент вызова, как передать данные в поток и почему Thread почти не используют в новом коде — стоит разобрать подробно.

Как это устроено

Thread — это обёртка над потоком операционной системы. Каждый созданный объект System.Threading.Thread соответствует одному OS-потоку со своим стеком (по умолчанию 1 МБ на x64).

Создать поток можно двумя способами — через ThreadStart или ParameterizedThreadStart:
// Без параметра
var t1 = new Thread(new ThreadStart(DoWork));

// С параметром типа object
var t2 = new Thread(new ParameterizedThreadStart(DoWorkWithParam));


После new Thread(...) поток ещё не запущен. Запуск происходит при вызове Start:
t1.Start();          // ThreadStart — без аргумента
t2.Start("hello"); // ParameterizedThreadStart — передаём object


Внутри метода поток получает управление не сразу: ОС ставит его в очередь планировщика. Поэтому код после Start() в вызывающем потоке продолжает выполняться параллельно.

Передача данных в поток

ParameterizedThreadStart принимает object — это неудобно, потому что нужно приводить тип внутри метода:
void DoWorkWithParam(object? state)
{
var message = (string)state!;
Console.WriteLine(message);
}


Более чистый способ — захват переменной через лямбду:
string data = "hello from closure";
var t = new Thread(() => Console.WriteLine(data));
t.Start();


Тут важно понимать: лямбда захватывает ссылку на переменную, а не значение. Если data изменится до того, как поток до неё доберётся, поток увидит новое значение.

Фоновые и foreground-потоки

По умолчанию Thread создаётся как foreground (IsBackground = false). Это значит, что процесс не завершится, пока поток не закончит работу. Если нужно обратное поведение:
var t = new Thread(DoWork);
t.IsBackground = true;
t.Start();


Фоновый поток будет убит принудительно при выходе из основного потока.

Подводные камни

Thread.Abort() удалён начиная с .NET 5 — он бросал ThreadAbortException в произвольном месте и приводил к непредсказуемому состоянию программы. Для отмены нужно использовать CancellationToken.

Совместный доступ к данным между потоками требует синхронизации. Без неё возникают гонки, которые воспроизводятся нестабильно и тяжело отлаживаются:
int counter = 0;
var t1 = new Thread(() => { for (int i = 0; i < 10000; i++) counter++; });
var t2 = new Thread(() => { for (int i = 0; i < 10000; i++) counter++; });
t1.Start(); t2.Start();
t1.Join(); t2.Join();
// counter будет меньше 20000 — это гонка
Console.WriteLine(counter);


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

Пример кода

Корректный вариант с отменой через CancellationToken:
var cts = new CancellationTokenSource();

var t = new Thread(() =>
{
while (!cts.Token.IsCancellationRequested)
{
Console.WriteLine("Working...");
Thread.Sleep(500);
}
Console.WriteLine("Stopped.");
});

t.IsBackground = true;
t.Start();

Thread.Sleep(2000);
cts.Cancel();
t.Join();


Thread.Start запускает OS-поток, но не гарантирует немедленное выполнение. Данные лучше передавать через замыкания, а не через ParameterizedThreadStart. Для большинства задач сегодня используют Task, async/await или ThreadPool — они не блокируют поток в ожидании и экономят ресурсы.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека шарписта

#sharp_view
  • 👍 9
  • ❤ 8
  • ❤‍🔥 2
  • 👏 1
More from @csharpproglib
  1. Sep 21, 2026⚙️ Настоящие атомарные операции Если Volatile решает проблему видимости, то Interlocked ре…
  2. Sep 20, 2026💪 Разминка перед трудовыми буднями Что произойдёт? ❤️ — список станет [1, 3] 🔥 — Invalid…
  3. Sep 19, 2026🧩 Middleware в ASP.NET Core: 3 ловушки Middleware — звено HTTP pipeline: app.Use(async (c…
  4. Sep 18, 2026📍 Навигация: Вакансии • Задачи • Собесы 🐸Библиотека шарписта #garbage_collector
  5. Sep 17, 2026🦆 Duck typing в C# — почти как в TypeScript В TypeScript достаточно, чтобы у объекта был…
  6. Sep 17, 2026🧠 Почему .NET-под съедает всю память? kubectl top pod показывает 1 ГБ, а managed heap зан…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →