两个线程可以调用同一个DLL中的两个函数吗?
Posted
技术标签:
【中文标题】两个线程可以调用同一个DLL中的两个函数吗?【英文标题】:Can two functions in same DLL be called by two threads? 【发布时间】:2014-08-27 22:57:23 【问题描述】:我用Visual C++ 2008写了一个DLL MyDLL.dll,如下:
(1) MFC 静态链接 (2) 使用多线程运行库。
在DLL中,这是两个导出函数共享的全局数据m_Data,如下:
ULONGLONG WINAPI MyFun1(LPVOID *lpCallbackFun1)
...
Write m_Data(using Critical section to protect)
…
return xxx;
ULONGLONG WINAPI MyFun2(LPVOID *lpCallbackFun2)
...
Suspend MyThread1 to prevent conflict.
Read m_Data(using Critical section to protect)
Resume MyThread1.
…
return xxx;
在我的主应用程序中,它会先调用LoadLibrary来加载MyDLL.dll,然后获取MyFun1和MyFun2的地址,然后做如下事情:
(1) 启动一个新线程MyThread1,它会调用MyFun1来做一个耗时的任务。 (2) 启动一个新线程MyThread2,会多次调用MyFun2,如下:
for (nIndex = 0; nIndex = 20; nIndex)
nResult2 = MyFun2(lpCallbackFun2);
NextStatement2;
虽然 MyThread1 和 MyThread2 使用临界区来保护共享数据 m_Data,但我仍然会在访问共享数据之前暂停 MyThread1,以防止任何可能的冲突。
问题是:
(1) MyFun2第一次调用时,一切正常,MyFun2(即nResult2)的返回值为1,符合预期。 (2) MyFun2第二、三、四次invoke时,MyFun2中的操作执行成功,但MyFun2(即nResult2)的返回值是随机值,而不是期望值1。我尝试使用Debug来跟踪到 MyFun2,并确认最后一个 return 语句只是返回一个值 1,但是调用者在检查 nResult2 时将收到一个随机值而不是 1。 (3) MyFun2 第四次调用后返回 MyFun2 后面的下一条语句,无论下一条语句是什么,我总是会得到“buffer overrun detected”的错误。
我认为这看起来像是堆栈损坏,因此请尝试进行一些测试:
-
我确认编译器中的 /GS(堆栈安全检查)功能已开启。
如果在 MyThread1 中的 MyFun1 完成后调用 MyFun2,则一切正常。
在调试模式下,MyFun2 中读取共享数据 m_Data 的代码行不会导致任何错误或异常。 MyFun1 中写入共享数据的代码行也不会。
那么,如何解决这个问题
谢谢!
【问题讨论】:
我不知道您的问题,可能是您未显示的大型代码中的一个无关问题。但是请不要暂停其他线程,那将导致灾难! 临界区将在需要时停止和恢复线程,前提是它们被正确使用。 你使用SuspendThread()
函数吗?
问题解决了,我获取到函数地址后,缺少WINAPI修饰符。
【参考方案1】:
我想在这一行
Suspend MyThread1 to prevent conflict.
您正在使用SuspendThread() 函数。这就是它的文档所说的:
这个函数主要是为调试器设计的。 它不适用于线程同步。如果调用线程尝试获取挂起线程拥有的同步对象,则在拥有同步对象(例如互斥锁或临界区)的线程上调用 SuspendThread 可能会导致死锁。为避免这种情况,应用程序中不是调试器的线程应向其他线程发出信号以暂停自身。目标线程必须设计为监视此信号并做出适当的响应。
所以,简而言之:不要使用它。关键部分和其他同步对象可以正常工作。
【讨论】:
【参考方案2】:永远不要使用 SupsendThread!!!绝不! SuspendThread 仅用于调试目的。
原因很简单。你不知道你在哪里暂停线程。当线程阻塞您要使用的资源时,它可能是及时的。还有一堆 CRT 函数使用线程同步。 只需使用关键的 sectins 或 mutexes。
只需在此处查看简单示例:http://blog.kalmbachnet.de/?postid=6 和此处 http://blog.kalmbachnet.de/?postid=16
【讨论】:
【参考方案3】:由于这是一个 windows 程序,您可以在读取或写入共享数据时使用基于 windows 的互斥锁或信号量和 WaitForSingleObject。
【讨论】:
以上是关于两个线程可以调用同一个DLL中的两个函数吗?的主要内容,如果未能解决你的问题,请参考以下文章