在加载上下文中加载非托管静态 dll [英] Load unmanaged static dll in load context
问题描述
我有本机非托管 dll,它是静态的,如果我想并行运行它,每次我需要库来做一些工作时都必须加载它.在 .NET 中,我会使用 AppDomain 并在需要时加载此 dll,但在 NET Core 中 AppDomains 已消失(目前).我查看了 AssemblyLoadContext,但没有与 LoadUnmanagedDll 相关的适当文档.netstandard1.6可以做到吗?
I have native unmanaged dll which is static and must be loaded each time when I need library to do some work if i want to run it in parallel. In .NET I would use AppDomain and load this dll when i need it, but in NET Core AppDomains are gone (for now). I have looked at AssemblyLoadContext but there is no proper documentation with LoadUnmanagedDll. Can this be done in netstandard1.6?
编辑当前代码使用 PInvoke 调用并且运行良好.问题是因为这个不受管理的 dll 的性质,当我尝试并行调用它时会抛出 AccessViolationException,因为两个或多个任务想要访问相同的内存.
Edit Currently code is called with PInvoke and is working perfectly. Problem is because nature of this unmanged dll, when I try to call it in parallel throws AccessViolationException because two or more task wants to access same memory.
如果我可以在某些上下文中为每次加载 dll 然后调用 PInvoke,那么这个问题就会消失.
If I could load dll for each time that in some context and then call PInvoke on that this problem would be gone.
推荐答案
一种方法:
- 从
System.Runtime.Loader.AssemblyLoadContext
派生类 - 覆盖
Load(AssemblyName assemblyName)
调用LoadFromAssemblyPath()
或返回 null 以回退到默认上下文 - 覆盖
IntPtr LoadUnmanagedDll(string unmanagedDllName)
调用LoadUnmanagedDllFromPath()
来加载你的原生 dll - 间接访问您的 pinvoke 方法并通过一些已知的
接口
加载本机/非托管库
- Derive class from
System.Runtime.Loader.AssemblyLoadContext
- Override
Load(AssemblyName assemblyName)
callingLoadFromAssemblyPath()
or returning null to fallback on default context - Override
IntPtr LoadUnmanagedDll(string unmanagedDllName)
callingLoadUnmanagedDllFromPath()
to load your native dll - Indirectly access your pinvoke methods and load the native/unmanaged library through some known
interface
第四步是你需要根据现有代码的结构进行调整的部分.就我而言,我创建了 3 个程序集:
Step 4 is the part you need to adjust based on the structure of the existing code. In my case, I created 3 assemblies:
- 调用代码
- Pinvoke 代码
- 前两者共享的接口
在调用代码中:
var assem = assemblyLoadContext.LoadFromAssemblyName(new
System.Reflection.AssemblyName(pinvokeAssemblyName));
var type = assem.GetType(nameOfTypeThatCallsPinvoke);
return (ISharedInterface)Activator.CreateInstance(type);
当 nameOfTypeThatCallsPinvoke
的实例尝试使用 pinvoke 方法时,将调用加载上下文上的 LoadUnmanagedDll()
覆盖.
When instance of nameOfTypeThatCallsPinvoke
attempts to use pinvoke method your LoadUnmanagedDll()
override on the load context will get called.
需要共享接口,以便在编译时知道类型.如果调用代码直接引用 pinvoke 库,它的类型将与通过加载上下文获得的类型不同.
The shared interfaces are needed so types are known at compile-time. If the calling code references the pinvoke library directly it's types will differ from those obtained through the load context.
参考文献:
- AssemblyLoadContext 设计文档
- 关于使用 AssemblyLoadContext 加载插件的帖子(github 上的代码)
- 发布关于将 AssemblyLoadContext 与本机库一起使用 (github 上的代码)(免责声明:我的)
- AssemblyLoadContext design doc
- Post about using AssemblyLoadContext to load plugins (code on github)
- Post about using AssemblyLoadContext with a native library (code on github) (Disclaimer: mine)
这篇关于在加载上下文中加载非托管静态 dll的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!