Что такое мьютекс и какую проблему он решает в многопоточности

Ответ

Мьютекс (от англ. mutual exclusion — взаимное исключение) — это примитив синхронизации, который гарантирует эксклюзивный доступ к общему ресурсу для нескольких потоков. Он решает проблему состояния гонки (race condition), когда результат выполнения программы зависит от непредсказуемого порядка выполнения потоков.

Принцип работы:

  1. Поток, которому нужен доступ к ресурсу, пытается «захватить» мьютекс.
  2. Если мьютекс свободен, поток захватывает его, выполняет работу с ресурсом (входит в критическую секцию) и затем «освобождает» мьютекс.
  3. Если мьютекс уже захвачен другим потоком, текущий поток блокируется и ожидает его освобождения.

Пример на Python с threading.Lock:

import threading

# Общий ресурс
counter = 0
# Мьютекс для защиты ресурса
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        # with автоматически захватывает и освобождает мьютекс
        with lock:
            counter += 1

threads = [threading.Thread(target=increment) for _ in range(10)]

for t in threads:
    t.start()
for t in threads:
    t.join()

# Без мьютекса результат был бы непредсказуем
print(f"Итоговое значение: {counter}") # Гарантированно 1000000

Использование мьютекса обеспечивает атомарность операций в критической секции, делая код потокобезопасным.

Ответ 18+ 🔞

А, слушай, про мьютексы, да? Ну это такая штука, чтобы потоки друг другу в тарелку не срали, когда к одному и тому же куску памяти лезут. Взаимное исключение, блядь, как с одним сортиром на десять человек — пока один сидит и срёт, остальные ждут снаружи, терпят, блядь, скрепя зубами.

Вот представь: у тебя есть переменная counter, и десять потоков её одновременно увеличивают. Без мьютекса — это пиздец, бардак и состояние гонки. Один поток прочитал значение, второй в это же время его же прочитал, оба прибавили единичку и записали обратно. И вместо двух прибавлений получилось одно, понимаешь? Всё, пиши пропало, результат — хуйня полная, а не миллион.

А с мьютексом — красота. Он как вышибала у входа в критическую секцию: «Ты куда, сука? Ресурс занят! Стоять, ждать!». Поток захватил замок, сделал свои делишки, отпустил — следующий заходит. Порядок, блядь, а не анархия.

Смотри, как это на Питоне выглядит, там просто до безобразия:

import threading

# Общий ресурс
counter = 0
# Мьютекс для защиты ресурса
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        # with автоматически захватывает и освобождает мьютекс
        with lock:
            counter += 1

threads = [threading.Thread(target=increment) for _ in range(10)]

for t in threads:
    t.start()
for t in threads:
    t.join()

# Без мьютекса результат был бы непредсказуем
print(f"Итоговое значение: {counter}") # Гарантированно 1000000

Видишь этот with lock:? Это гениально, ёпта. Вошёл — сделал — вышел, и даже если посередине исключение выскочит, мьютекс всё равно отпустится. Не то что в каких-то других языках, где можно забыть его разлочить и потом всю систему повисшую искать, блядь.

Вот и вся магия. Захватил — поработал — отпустил. Атомарность, потокобезопасность, и все довольны. Главное — не забудь его отпустить, а то остальные потоки так и будут висеть в ожидании, пока их по таймауту не убьёт.