本文介绍了死锁发生在函数作用域静态变量(VC ++中的线程不安全)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题是当函数在多个线程上被调用时如何构造函数级静态函数?



问题描述:死锁发生,我的应用程序没有终止。在局部静态变量的初始化期间,它尝试获取MSVCR80!_lock,从不会锁定。



!在WinDbg中的locks命令提供以下输出。

CrtSec ntdll!LdrpLoaderLock + 0 at 7c97e178

LockCount 0



RecursionCount 1



OwningThread 1998



EntryCount d



ContentionCount d



* 已锁定



CritSec MSVCR80!__ app_type + 94 at 781c3bc8



LockCount 1



RecursionCount 1



OwningThread 9a8



EntryCount 1



ContentionCount 1



* 已锁定



下面是调用堆栈,您将看到它永远不会被锁住_mlock





**

**



781c3bc8 78132bd9 0777fde4 ntdll!RtlEnterCriticalSection + 0x46



00000008 b87d2630 00000000 MSVCR80!_lock + 0x2e



0864ae10 08631d7f 0864ae10 EPComUtilities32! _onexit + 0x36



0864ae10 b87d2588 00000001 EPComUtilities32!atexit + 0x9



0777fea8 0864719f 08630000 EPComUtilities32!XCriticalSectionEx :: ThreadTerminated + 0x5f



08630000 00000003 00000000 EPComUtilities32!DllMain + 0x20



08630000 7c90118a 08630000 EPComUtilities32!__ DllMainCRTStartup + 0x7a

08630000 00000003 00000000 EPComUtilities32!_DllMainCRTStartup + 0x1d



**

**



000000b0 00000000 00000000 ntdll!ZwWaitForSingleObject + 0xc



000000b0 ffffffff 00000000 kernel32!WaitForSingleObjectEx + 0xa8



000000b0 ffffffff 06ce64e0 kernel32!WaitForSingleObject + 0x12



000480ba 000f4240 00000000 CATSysMultiThreading!CATThreads :: Join + 0xf5



0012fcc8 00000004 00000000 JS0GROUP!CATLM :: StopHB + 0xf4



d138509f 00416694 00000001 JS0GROUP!CATLM :: Unmake + 0x6b



00000000 00000000 00000000 MSVCR80!_cinit + 0xd6



00000000 0012fd6c 081e68d9 MSVCR80!exit + 0xd



00000000 06d404f0 0998fb90 JS0GROUP!CATExit + 0x1d



00000000 004ef366 0000000d DNBPLMProvider!DNBEPLMTransactionMgt :: OnApplicationExit + 0x229



00000000 0012fd9c 004eabfc JS0GROUP!CATCallExits + 0x2bc



00000000 0012ff7c 0040cefd JS0GROUP!CATErrorNormalEnd + 0x31 00000000 06ce71d0 06ce71d0 JS0GROUP!CATExit + 0xc



00000007 06cdb120 059b61d8 DLMMfgContextSolver!main + 0x146d



ffffffff ffffffff bffde000 DLMMfgContextSolver!__ tmainCRTStartup + 0x10f

  //下面的代码片段
void main()
{

atexit(MyCallBack);
exit(0);

}

void MyCallBack()
{

// Waitingforsingleobject()//等待所有线程终止

}

EXE调用DllMain和DLL_THREAD_DETACH标志,

  BOOL APIENTRY DllMain(HANDLE,DWORD dwReason,LPVOID)
{
if(dwReason == DLL_THREAD_DETACH)
{
F1();
F2();
}
}

F1()
{

const static CComBSTR bstrMethod = __ FUNCTION __;

}

F2()
{

const static CComBSTR bstrMethod = __ FUNCTION __;

}

线程是否可以在函数内部进行本地静态初始化。另外我注意到,如果静态变量是一次初始化之前的exit()主应用程序我没有看到任何问题。可以任何一个请解释可能是什么问题?



注意:但是当我使静态变量作为非静态死锁不会发生,问题解决。 >

还让我知道在这种情况下可能有帮助的任何替代解决方案
热切等待回复。

解决方案

在某种意义上,这个问题已经由弗拉德的意见回答了你的问题:不要在DllMain做任何事情(如果可能的话)。



你真的受到DllMain中的明显限制,涉及深入到另一个Dll(包括使用malloc等)的任何东西都出来了。事实上,你可以做的唯一的事情是:调用Kernel32.dll(除了加载/卸载Dlls!)和初始化简单的数据类型。



我真的认为



希望这会有帮助,

p> ps



来自MSDN博客的额外链接:


The question is how function-level statics are constructed when the function is called on multiple threads?

Problem Description: Deadlock occurs and my application doesn't get terminated. During initialization of local static variable it tries to acquire MSVCR80!_lock and never gets hold on the lock.

!locks command in WinDbg gives the following output.

CritSec ntdll!LdrpLoaderLock+0 at 7c97e178
LockCount 0

RecursionCount 1

OwningThread 1998

EntryCount d

ContentionCount d

* Locked

CritSec MSVCR80!__app_type+94 at 781c3bc8

LockCount 1

RecursionCount 1

OwningThread 9a8

EntryCount 1

ContentionCount 1

* Locked

Below is the calls stack and you will see that it will never get hold on the lock _mlock

#

**

**

781c3bc8 78132bd9 0777fde4 ntdll!RtlEnterCriticalSection+0x46

00000008 b87d2630 00000000 MSVCR80!_lock+0x2e

0864ae10 08631d7f 0864ae10 EPComUtilities32!_onexit+0x36

0864ae10 b87d2588 00000001 EPComUtilities32!atexit+0x9

0777fea8 0864719f 08630000 EPComUtilities32!XCriticalSectionEx::ThreadTerminated+0x5f

08630000 00000003 00000000 EPComUtilities32!DllMain+0x20

08630000 7c90118a 08630000 EPComUtilities32!__DllMainCRTStartup+0x7a

08630000 00000003 00000000 EPComUtilities32!_DllMainCRTStartup+0x1d#

**

**

000000b0 00000000 00000000 ntdll!ZwWaitForSingleObject+0xc

000000b0 ffffffff 00000000 kernel32!WaitForSingleObjectEx+0xa8

000000b0 ffffffff 06ce64e0 kernel32!WaitForSingleObject+0x12

000480ba 000f4240 00000000 CATSysMultiThreading!CATThreads::Join+0xf5

0012fcc8 00000004 00000000 JS0GROUP!CATLM::StopHB+0xf4

d138509f 00416694 00000001 JS0GROUP!CATLM::Unmake+0x6b

00000000 00000000 00000000 MSVCR80!_cinit+0xd6

00000000 0012fd6c 081e68d9 MSVCR80!exit+0xd

00000000 06d404f0 0998fb90 JS0GROUP!CATExit+0x1d

00000000 004ef366 0000000d DNBPLMProvider!DNBEPLMTransactionMgt::OnApplicationExit+0x229

00000000 0012fd9c 004eabfc JS0GROUP!CATCallExits+0x2bc

00000000 0012ff7c 0040cefd JS0GROUP!CATErrorNormalEnd+0x31 00000000 06ce71d0 06ce71d0 JS0GROUP!CATExit+0xc

00000007 06cdb120 059b61d8 DLMMfgContextSolver!main+0x146d

ffffffff ffffffff bffde000 DLMMfgContextSolver!__tmainCRTStartup+0x10f

// Code snippet below 
void main() 
{

    atexit(MyCallBack); 
    exit(0); 

}

void MyCallBack() 
{

// Waitingforsingleobject() // Waits until all threads are terminated

}

The EXE call DllMain with DLL_THREAD_DETACH flag and we have an explicit handling as shown below

BOOL APIENTRY DllMain( HANDLE, DWORD dwReason, LPVOID ) 
{
  if(dwReason == DLL_THREAD_DETACH) 
  { 
    F1();
    F2();
  }
}

F1()
{

    const static CComBSTR bstrMethod = __ FUNCTION __ ;

}

F2()
{

    const static CComBSTR bstrMethod = __ FUNCTION __ ;

}

Is it thread safe to have local static initialization within a function. Also I noticed if static variable is once initialized before the exit() of main application I don't see any problem. Can any one please explain what might be issue?

Note: But when I make static variable as non static the deadlock doesn't occur and problem is solved.

Also let me know any alternate solution which might help in this situationEagerly waiting for reply.

解决方案

In a sense, this question has been answered by Vlad's comments to your question: Don't do anything (if at all possible) in DllMain.

You're really limited by what's sensible in DllMain, Anything involving delving into another Dll (including using malloc etc) is out. In fact about the only things you can do are: make calls into Kernel32.dll (except for loading/unloading Dlls!) and initialising simple datatypes.

I really think that given your description of the problem, using CComBSTR's is breaking one or more of these rules.

Hope this helps,

p.s.

An extra link from MSDN blogs:http://blogs.msdn.com/oleglv/default.aspx

这篇关于死锁发生在函数作用域静态变量(VC ++中的线程不安全)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-11 04:00