有没有一种更简单的方法来实例化静态库

Is there a simpler way of instancing a static library?

本文关键字:方法 实例化 静态 更简单 一种 有没有      更新时间:2023-10-16

我有一个静态C库,我需要它来运行多线程(线程之间没有交互,我只需要同时使用多个线程来更快地完成任务)。此外,我还将c库封装到一个c++cli库中,然后由c#main应用程序使用。

由于静态库不能很好地响应通过它运行的多个线程(这超出了我的控制范围,我没有它的依赖项的来源),我已经多次复制(略有变化)整个过程,并在c++cli库(及其副本)和c应用程序之间放置另一个包装器,该应用程序将副本模拟为对象的多达8个实例。它很有效,但对库的功能进行任何更改都相当粗糙和繁琐。

有人知道有什么更简单的方法可以达到同样的效果吗?我的最佳猜测是,一些静态内存是在同一库中工作的多个线程之间发生冲突的地方,有没有办法强制所有静态变量都是线程特定的?(无法在其中添加declspec线程)。

由于您通过C++/CLI层从C#使用C库,因此您的链接关系听起来像这样:

(C#应用程序)--动态-->(C++/CLI DLL)--静态-->(C库)

背景:

因为你说你没有办法修改或以其他方式修复你的C库,所以如果不以某种方式在内存中复制C库,你真的没有办法解决线程安全问题,这将有效地复制全局数据,而全局数据肯定会导致线程冲突。

无论你怎么看,通过DLL复制(你目前的方法)解决这个问题的唯一方法都需要你提前知道你需要多少个复制,而这些DLL中的每一个都需要稍微不同的导出符号名称(例如,每个DLL都需要一个不同的类或名称空间名称作为你的C++/CLI托管对象类)。正如你所说,这确实很粗糙(我将补充一点,很难管理,也不可能扩大规模)。

解决方案:

我认为你更好更干净的选择是通过EXE复制。为此,您将在C++/CLI DLL前面插入一个新的EXE,并通过您选择的IPC机制(C#中的IPC机制-使用和最佳实践)动态链接到它。让我们将此EXE称为您的服务EXE。如果为主C#应用程序中的每个线程实例化一个服务EXE,那么每个服务EXE都将加载其自己的C++/CLI DLL副本,从而加载其自己版本的C库。这意味着每个线程都通过服务EXE对C库的副本进行操作。

以下是您的链接关系:

(C# application)--IPC-->(C# service EXE)--dynamic-->(C++/CLI DLL)--static-->(C library)

在物理文件方面,它看起来是这样的:

MainApp.exe--IPC-->ServiceApp.exe--dynamic-->CppCliWrapper.dll

要优化此解决方案,您应该尽量避免创建/删除繁重的线程,因为这涉及到创建/删除服务EXE。例如,您可以在启动时预先分配X个线程,并在整个应用程序生命周期中使用这些线程。您还可以考虑对操作进行批处理,以优化IPC开销。所有这些都取决于您的应用程序的需求和细节。

更进一步地说,如果您选择通过TCP/IP工作的IPC机制,您可能会在机器之间扩展此解决方案。然后,您可以将操作分散到任意数量的机器上。这就是许多公司将DLL转变为水平可扩展服务的方式。这并不像听起来那么容易,但食物是为了以防万一你需要扩大规模。

问题似乎是库不是可重入的。如果您可以访问库的源代码,那么最好搜索所有全局变量,并使它们成为线程本地变量。这可以在C++11上使用thread_local关键字来完成,如果使用gcc/g++进行编译,则可以使用__thread关键字来完成。

这样可以确保在每个线程上使用每个全局变量的不同副本。