c# - 如何创建多线程 Dll

标签 c# c++ .net multithreading dll

我有一个 Dll 可以从磁盘读取文件并返回它的内容:

mydll.h:

extern "C" __declspec(dllexport) void InitFile3dPoints(wchar_t* i_file);
extern "C" __declspec(dllexport) int GetNumPointsForSurface(int i_surf_index);
extern "C" __declspec(dllexport) void GetPointsForSurface
    (double* o_result, int i_resultLength, int i_surf_index);

mydll.cpp:

File3dPoints file_3dPoints;

void InitFile3dPoints(wchar_t* i_file) 
          { file_3dPoints = readFile3dObjectFromDisk(i_file) }
int GetNumPointsForSurface(int i_surf_index) 
          { return file_3dPoints[i_surf_index].getNumPoints(); }

void GetPointsForSurface(double* o_result, int i_resultLength, int i_surf_index);
{
  const int num_points = file_3dPoints[i_surf_index].getNumPoints();
  if (num_points < i_resultLength)
    return;

  for (int i = 0; i < num_points; ++i)
    o_result[i] = file_3dPoints[i_surf_index].getPoint(i);
}

客户端.cs:

IntPtr inst = LoadLibrary("mydll.dll");
InitFile3dPoints(filename);

for (int i = 0; i < n; ++i)
{
  int num_points_for_surface = GetNumPointsForSurface(i);
  double[] points = new double[num_points_for_surface];
  GetPointsForSurface(points, points.Length, i);
  // some code
}
FreeLibrary(inst);

我的 dll 不是线程安全的。一个线程可以调用 InitFile3dPoints。在调用 GetPointsForSurface 之前,另一个线程可以调用 InitFile3dPoints。 你能告诉我如何让它成为线程安全的吗?创建用于访问 file_3dPoints 的互斥量不会解决问题,我需要 mydll.cpp 中的每个线程都有其 file_3dPoints 的拷贝。

谢谢

最佳答案

有很多选择可以做到这一点。

首先也是最重要的是不要使用全局变量,它们是一场噩梦(出于这个和其他原因)。让我们开始更改 InitFile3dPoints 签名以分配所需的内存并将其返回给调用者(因此地址可以用作“句柄”):

File3dPoints* InitFile3dPoints(const wchar_t* i_file) 
{
    return readFile3dObjectFromDisk(i_file);
}

请注意,readFile3dObjectFromDisk 必须返回类型为 File3dPoints 的堆分配对象。

然后更改每个函数以接受该指针:

int GetNumPointsForSurface(const File3dPoints* data, int i_surf_index) 
{
    return *data[i_surf_index].getNumPoints(); 
}

File3dPoints* 可以在 C# 中使用 IntPtr 编码:

IntPtr inst = LoadLibrary("mydll.dll");
IntPtr data = InitFile3dPoints(filename);

最后不要忘记在释放数据的地方添加一个 DisposeFile3dPoints 函数:

void DisposeFile3dPoints(File3dPoints* data)
{
    if (data != NULL)
        delete data;
}

一般来说,要使 DLL 成为“线程安全的”(根据您的问题的上下文),您应该使每个函数都是独立的(它需要的所有数据都来自其参数,它没有任何本地静态变量也不是全局的)。请注意,这并不能使它在任何更广泛的意义上真正成为线程安全的(例如,如果您将向该数据公开一个写函数,那么您仍然需要保护访问,但它可以更容易地完成C# 端)。

您可以更好地将所有这些函数包装在一个 C# 类中,用户甚至不会看到:

public class File3D : IDisposable
{
    public File3D(string path)
    {
        // Initialize. Call InitFile3dPoints
    }

    ~File3D()
    {
        // Call Dispose(false)
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private IntPtr _data;

    private void Dispose(bool disposing)
    {
        // Unmanaged resource, ignore disposing parameter
        // and call DisposeFile3dPoints
    }
}

关于c# - 如何创建多线程 Dll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16896436/

相关文章:

C# 显式定义抛出哪些异常

c# - .NET:延迟后在 UI 线程上执行 lambda 的最佳方式?

.net - 如何调用仅在运行时已知的类的静态方法

c# - 如何序列化 List<T>?

c# - parentForm Reference怎么为null?

c++ - 32 位应用程序中的 64 位功能?

c++ - 将 vs printf 放在以下代码中?

.net - WinForms 相当于 HTML <optgroup>

c# - SQL Server 地理结果格式

c++ - C++ 中的组合运算符重载?