DLL 线程安全

Posted

技术标签:

【中文标题】DLL 线程安全【英文标题】:DLL thread safety 【发布时间】:2011-01-02 15:58:30 【问题描述】:

我正在使用 MS VC express c++ 开发一个 DLL,它将同时加载到多个客户端应用程序中,该 DLL 具有使用 data_seg(".SHARED_SPACE_NAME") 创建的共享内存空间。在这个共享内存空间中有一些可以修改的向量。 假设我们在 DLL 主体中有一个名为 doCalc() 的函数:

_DLLAPI void __stdcall doCalc(int argument)  
  
    //Add to vector  
    //Loop through vector  
    //Erase from vector  
    //etc.  

如果同时从两个或多个客户端应用程序调用doCalc,系统将崩溃。 我希望 doCalc 调用“排队等待”以完成上一个调用 - 就像它是一个单线程应用程序一样。 因此,如果客户端 1 调用,然后在客户端 2 调用之后立即调用,那么客户端 1 应该完成该函数,然后客户端 2 应该运行该函数。

最好的解决方案是将 DLL 作为单线程运行,但我在互联网上搜索过,我认为这是不可能的。

我已经尝试在互联网上搜索这个问题,并且我想出了一些关于使函数 static 使其线程安全的方法。

我还读到 C++0x 会以某种方式使这个线程安全。但是 MS VC express 不支持它。

我没有多线程方面的经验,所以希望你能提供帮助。提前致谢。

【问题讨论】:

不建议共享这样的 C++ 类。您必须对 std::vector 的特定运行时版本的实现有相当多的了解才能使代码安全,因此通常不要这样做。在大多数情况下,创建一个包装器来访问您的共享内容要安全得多。 这种hackery完全超出了C++的范围,包括C++0x。此外,std::vector<T>从不是共享data_seg 的一部分。也就是说,number 个元素可能是共享的,但 T 元素的数组本身却不是。您需要编写 shared_allocator 以便正确共享 std::vector<T, shared_allocator>。这是不平凡的。 【参考方案1】:

此处使用的 Windows API 将是 CreateMutex。创建一个命名的互斥对象。由于需要操作共享数据,请使用互斥量句柄调用 WaitForSingleObject,完成后调用 ReleaseMutex。每个调用 WaitForSingleObject 的线程都获得了互斥锁的所有权,而任何其他调用 WaitForSingleObject 的线程都将停止,直到拥有的线程调用 ReleaseMutex。

当然,我不相信你可以做你想做的事:

    Dll 可以映射到每个进程空间的不同地址。如果是这样,所有的指针都会不正确。 C++ 不允许对分配进行细粒度控制,并且有许多隐式分配,尤其是在处理 STL 对象时。我不相信您可以获取向量以将所有相关数据存储在共享区域中。

您将不得不使用 C 样式的原始数组来执行此操作。

【讨论】:

Mutex 是否在 Visual Studio Express 中可用?你知道互斥体的任何好例子吗?我在谷歌上找不到任何好的。 整个 windows API 在 Sutdio Express 上可用。不包括 MFC 框架,以及资源编辑器等一些愚蠢的东西。【参考方案2】:

看起来您需要一个系统范围的 mutex 来保护您的关键代码部分(不能同时运行的代码)。将函数设为静态与它无关,因为它不会阻止不同的应用程序同时运行它。

【讨论】:

Windows 术语中的“命名互斥锁”。 CreateMutex() 的 lpName 参数。【参考方案3】:

我认为Boost.Interprocess 正是您所需要的。它将同时解决同步问题,以及 Jim Brissom 在他的评论中所说的你甚至还没有想到的问题。

【讨论】:

以上是关于DLL 线程安全的主要内容,如果未能解决你的问题,请参考以下文章

使用 fortran dll 的线程安全 C# 服务

安全之路 —— 无DLL文件实现远程线程注入

安全之路 —— 利用远程线程注入的方法(使用DLL)实现穿墙与隐藏进程

从哪里获得线程安全的 Ghostscript 编译?

在线程中使用 std::string 函数是不是安全? (c++)

单例模式和线程安全