🚦 Структура семафора SemLockObject, в реализации модуля multiprocessing, поддерживает внутреннее поле счетчика count. При работе в качестве рекурсивного мьютекса (RECURSIVE_MUTEX) count — это количество раз, когда поток захватывал мьютекс (т. е. 0, 1, .. N). А при работе в качестве семафора (SEMAPHORE) счетчик часто равен 0 или 1, но может быть отрицательным, если SemLockObject инициализируется с maxvalue > 1.
🔄 Изменение count не является потокобезопасным без GIL внутри процесса. Обратите внимание, что поле count не является общим для всех процессов, в отличие от базового поля sem_t или HANDLE.
☠️ В частности, в этом коде изменение count, после освобождения семафора, не является потокобезопасным без GIL:
⛔️ Это может быть источником взаимоблокировок при работе с отключенным GIL.
💁♂️ Кажется немного странным вставлять блокировку в реализацию блокировки, но на удивление сложно сделать так, чтобы изменения считались потокобезопасными, особенно в случае использования kind == SEMAPHORE, когда несколько потоков могут "освободить" семафор одновременно.
👌 Для решения этой проблемы использованы CRITICAL_SECTION, чтобы обеспечить потокобезопасность методов Acquire(), Release() и _count() модуля без GIL.
👉 Подробнее в телеграм канале https://t.me/cpython_ru
#PEP703