1

ディスクからファイルを読み取り、その内容を返す 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);
}

client.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はスレッドセーフではありません。1 つのスレッドで InitFile3dPoints を呼び出すことができます。GetPointsForSurface を呼び出す前に、別のスレッドで InitFile3dPoints を呼び出すことができます。スレッドセーフにする方法を教えてください。file_3dPoints にアクセスするためのミューテックスを作成しても問題は解決しません。mydll.cpp に含まれるすべてのスレッドに file_3dPoints のコピーが必要です。

ありがとう

4

3 に答える 3

6

それを行うには多くのオプションがあります。

まず最も重要なことは、グローバル変数を使用しないことです。これは悪夢です (これと他の理由から)。署名を変更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*IntPtrC# で次のようにマーシャリングできます。

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
    }
}
于 2013-06-03T12:19:48.560 に答える
2

ミューテックスを使用してグローバル変数へのアクセスを保護します。いっそのこと、グローバル変数を使用しないでください。

于 2013-06-03T12:15:37.293 に答える