翻译 《The Old New Thing》 - Another reason not to do anything scary in your DllMain: Inadvertent

本文讲述了在DLL的DllMain函数中,由于加载器锁的存在可能导致的死锁问题,强调了在该函数中操作锁的谨慎性和遵循锁层次结构的重要性。
摘要由CSDN通过智能技术生成

Another reason not to do anything scary in your DllMain: Inadvertent deadlock - The Old New Thing (microsoft.com)icon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20040128-00/?p=40853

Raymond Chen 2004年01月28日


简介

这篇文章讨论了在DLL的DllMain函数中执行某些操作时可能发生的死锁问题

正文

        你的DllMain函数是在加载器锁内部运行的,这是操作系统允许你在其内部锁之一被持有时执行代码的少数几次机会之一。这意味着你必须格外小心,不要在你的DllMain中违反锁层次结构;否则,你就在自找死锁。 (你的DLL中确实有锁层次结构,对吧?)

        加载器锁是由任何需要访问进程中加载的DLL列表的函数获取的。这包括GetModuleHandleGetModuleFileName等函数。 如果你的DllMain进入了一个临界区或等待一个同步对象,而那个临界区或同步对象又由一些代码拥有,而这些代码又在等待加载器锁,那么你就刚刚创建了一个死锁:

// 全局变量
CRITICAL_SECTION g_csGlobal;
// 某处的一些代码
EnterCriticalSection(&g_csGlobal);
... GetModuleFileName(MyInstance, ..);
LeaveCriticalSection(&g_csGlobal);

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,
                     LPVOID lpvReserved)
{
    switch (fdwReason) {
        ...
        case DLL_THREAD_DETACH:
            EnterCriticalSection(&g_csGlobal);
            ...
    }
    ...
}

        现在想象一下,某个线程正在愉快地执行第一段代码,并进入了g_csGlobal,然后挂起。在此期间,另一个线程退出了。这会进入加载器锁,并在仍然持有加载器锁的情况下发送出DLL_THREAD_DETACH消息。你接收到DLL_THREAD_DETACH并尝试进入你的DLL的g_csGlobal。这会在第一个线程上阻塞,该线程拥有临界区。那个线程随后恢复执行并调用GetModuleFileName。这个函数需要加载器锁(因为它正在访问加载到进程中的DLL列表),所以它被阻塞了,因为加载器锁已经被别的线程拥有了。

现在你遇到了一个死锁:

  • 第一个线程拥有g_cs,正在等待加载器锁。
  • 加载器锁被第二个线程拥有,正在等待g_cs

我亲眼见过这种问题发生,挺糟心的。

这件事告诉我们:谨慎看待加载器锁。如果你在DllMain中获取任何锁,请将其包含在你的锁层次结构规则中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x0007

可不可奖励我吃只毛嘴鸡 馋😋

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值