C # Блокировать потоки неуправляемого кода - PullRequest
2 голосов
/ 23 сентября 2011

Предположим, у нас есть неуправляемый процесс, который загружает управляемую DLL.В DLL есть необходимость блокировать некоторые или все потоки неуправляемого приложения для синхронизации одновременного доступа к некоторой памяти.Как можно заблокировать эти неуправляемые потоки?У меня есть только двоичный файл неуправляемого приложения, поэтому перекомпиляция невозможна.

1 Ответ

3 голосов
/ 23 сентября 2011

Обращаю ваше внимание на раздел "Замечания" в документации по API-функции SuspendThread :

Эта функция в первую очередь предназначена для использования отладчиками. не предназначен для синхронизации потоков. (выделено)

Это должно подсказывать вам, что то, что вы пытаетесь, является плохой идеей. Поэтому тот факт, что управляемый API для приостановки потоков ( Thread.Suspend ) оказался настолько проблематичным, что Microsoft на самом деле удалила его из .NET Framework.

Дело в том, что вы не можете безопасно приостановить поток в том же процессе, что и вы, без некоторого сотрудничества с этим потоком. Например, вы можете приостановить другой поток, пока он находится в процессе выделения памяти, и имеет блокировку структуры управления кучи. Bam: ваш поток будет тупиковым, если вы попытаетесь сделать что-нибудь , которое выделяет память, включая JIT-компиляцию вашего кода .NET. (А блокировка кучи - это просто один возможный тупик из многих. И есть условия гонки. Просто не делайте этого.)

Как сказал Ганс в комментариях выше, вы не можете реализовать потокобезопасный код путем приостановки потоков. Вы должны сотрудничать с другим потоком, разделяя объект синхронизации (мьютекс, тонкая блокировка чтения / записи, монитор и т. Д.), И чтобы обе стороны соответствующим образом сигнализировали этому объекту синхронизации, чтобы он сказал «Я начинаю получать доступ к этому общему ресурсу» и "Я задолбался". Если одна сторона не будет сотрудничать, то вы не сможете обеспечить безопасность нитей.


Если вы действительно должны приостановить работу своего неуправляемого приложения, чтобы обновить ячейки памяти, и вы действительно не можете взаимодействовать с этим приложением, то самым безопасным способом, вероятно, будет забыть о написании внутрипроцессной DLL и вместо этого посмотрите API отладчика . Вот статья, которая демонстрирует, как использовать некоторые из API отладчика из .NET.

Сделайте ваше приложение отдельным процессом, который подключается к неуправляемому приложению в качестве отладчика (либо подключаясь после запуска приложения, либо запуская приложение под управлением отладки), а затем может управлять им извне, как если бы вы были запуск неуправляемого приложения в отладчике Visual Studio - приостановка, изменение памяти, возобновление. Теперь, когда вы находитесь в отдельном процессе, вы не делите блокировку кучи (или большинство других проблем взаимоблокировки) с приложением, которое вы пытаетесь приостановить, поэтому причины, по которым следует избегать SuspendThread, в значительной степени исчезают. Поскольку вы пишете отладчик (своего рода), теперь уместен вызов SuspendThread.

Но вам все равно придется разбираться с условиями гонки самостоятельно. Тщательно продумайте, что произойдет, если другой поток находится на полпути к записи в ваш блок памяти. (Когда вы возобновите этот поток, он напишет вторую половину, повредив данные, которые вы только что поместили туда.) А что, если другой поток находится в середине чтения вашего блока памяти - если он читает первые несколько байтов, то принял решение на их основе, и собирается прочитать следующие несколько байтов? Если он просто читает эту память, имеет ее копию в своих регистрах и собирается записать ее обратно с изменениями? Остерегайтесь осторожно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...