Встречается на 33% собеседований по C#

Что такое многопоточность

Многопоточность — это способность программы выполнять несколько задач одновременно, используя несколько потоков выполнения в рамках одного процесса. Поток — это наименьшая единица обработки, которую операционная система может планировать независимо. В C# многопоточность реализуется через классы System.Threading.Thread, Task и Parallel, а также через async/await для асинхронных операций.

Как это работает

В однопоточной программе все инструкции выполняются последовательно. Многопоточность позволяет разделить работу на несколько потоков, которые могут выполняться параллельно на разных ядрах процессора (параллелизм) или переключаться так быстро, что создается впечатление одновременности (конкурентность). В C# потоки создаются явно или через пул потоков. Например:

csharp
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // Создание и запуск потока
        Thread thread = new Thread(PrintNumbers);
        thread.Start();
text
    // Основной поток продолжает работу
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine($"Main: {i}");
        Thread.Sleep(100);
    }
}

static void PrintNumbers()
{
    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine($"Thread: {i}");
        Thread.Sleep(100);
    }
}

}

text

Здесь два потока выводят числа, чередуясь, что демонстрирует конкурентное выполнение.

## Синхронизация и проблемы

При работе с общими данными несколько потоков могут обращаться к ним одновременно, что приводит к состоянию гонки (race condition), взаимным блокировкам (deadlock) и другим ошибкам. Для синхронизации в C# используются:

- `lock` — блокировка критической секции.
- `Monitor` — низкоуровневый механизм синхронизации.
- `Mutex` и `Semaphore` — для синхронизации между процессами.
- `Interlocked` — атомарные операции.
- `async`/`await` — для асинхронного программирования без явного управления потоками.

Пример с `lock`:

```csharp
class Counter
{
    private int _count = 0;
    private readonly object _lock = new object();

    public void Increment()
    {
        lock (_lock)
        {
            _count++;
        }
    }
}

Без lock одновременный вызов Increment из нескольких потоков может привести к потере обновлений.

Преимущества и риски

Многопоточность повышает производительность за счет использования многоядерных процессоров и улучшает отзывчивость приложений (например, UI не блокируется при длительных операциях). Однако она усложняет код: появляются проблемы синхронизации, сложнее отладка, возрастает потребление памяти. Поэтому важно использовать многопоточность только там, где она действительно нужна, и применять высокоуровневые абстракции, такие как Task и Parallel, которые упрощают управление потоками.

Примеры применения

  • Веб-серверы: обработка множества запросов одновременно.
  • Графические редакторы: фоновое выполнение рендеринга.
  • Игры: разделение логики, графики и ввода.
  • Научные вычисления: распараллеливание вычислений.

Коротко

  • Многопоточность — выполнение нескольких задач одновременно в рамках одного процесса.
  • Поток — минимальная единица обработки; в C# используются Thread, Task, Parallel.
  • Главные проблемы — состояние гонки и взаимные блокировки; решаются синхронизацией (lock, Monitor, async/await).
  • Преимущества: производительность и отзывчивость; недостатки: сложность и риск ошибок.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы