C#阻止非托管代码的线程

时间:2011-09-23 11:17:39

标签: c# multithreading block unmanaged

假设我们有一个非托管进程加载托管DLL。在DLL中,需要阻止非托管应用程序的一些或所有线程以同步对某些内存的并发访问。 如何阻止那些非托管线程?我只有非托管应用程序的二进制文件,因此无法重新编译。

1 个答案:

答案 0 :(得分:3)

我提请您注意SuspendThread API函数文档的“备注”部分:

  

此功能主要供调试器使用。它不打算用于线程同步。 (强调我的)

那应该告诉你,你正在尝试的是一个坏主意。因此,用于挂起线程的托管API(Thread.Suspend)的问题应该是如此,以至于Microsoft实际上从.NET Framework中删除了它。

事实是,如果没有来自该线程的一些合作,您无法在与您相同的进程中安全地挂起线程。举个例子,你可能会在分配内存的过程中暂停另一个线程,并锁定堆的控制结构。 Bam:如果你尝试做任何分配内存,你的线程将会死锁,其中包括JIT编译你的.NET代码。 (并且堆锁只是一个可能的死锁。存在竞争条件。只是不要这样做。)

正如Hans在上面的评论中所说,你不能通过挂起线程来实现线程安全的代码。您必须通过共享同步对象(互斥锁,超薄读取器/写入器锁,监视器等)与另一个线程合作,并让双方正确地发信号通知该同步对象说“我正在开始访问此共享资源”和“我受够了”。如果一方不合作,那么你就不能有线程安全。


如果您真的必须暂停您的非托管应用程序以更新内存位置,并且您真的无法获得该应用程序的合作,最安全的方法可能是忘记编写进程内DLL,而是查看 debugger API Here's一篇文章,演示如何使用.NET中的某些调试器API。

使您的应用程序成为一个独立的进程,作为调试器附加到您的非托管应用程序(通过在启动应用程序后附加,或通过在调试控制下启动应用程序),然后可以从外部控制它,就像您是在Visual Studio调试器下运行非托管应用程序 - 暂停,修改内存,恢复。现在您处于一个单独的进程中,您没有与您尝试暂停的应用程序共享堆锁(或大多数其他死锁问题) - 因此避免SuspendThread的原因很大程度上消失了。由于 正在编写调试器(各种类型),现在调用SuspendThread是合适的。

但你仍然需要自己处理比赛条件。仔细考虑如果另一个线程写入你的内存块的中途会发生什么。 (当你恢复那个线程时,它会写另一半,破坏你刚刚放在那里的数据。)如果另一个线程在读取你的内存块的中途 - 如果它读取前几个字节,做出决定怎么办?基于它们,并即将读取接下来的几个字节?如果它只是读取那个内存,它的寄存器中有一个副本,并且即将用更改将其写回来? Tread carefully.