2

C インターフェイスを備えた C++ ライブラリを開発しています。C インターフェイスには、次のものがあります。

  • ライブラリを初期化する関数 ( Init()— 指定されたパラメータで機能を実装するオブジェクトを構築します);
  • ライブラリを初期化解除する関数 ( DeInit() — そのオブジェクトを破壊する)、および;
  • オブジェクトの対応するメソッドを呼び出すだけのいくつかの関数 (たとえばFoo()Bar())。

クラス自体はスレッド セーフですが、C インターフェイス ( Init()DeInit()Foo()およびBar()) もスレッド セーフにする必要があります。

単一のグローバル変数、つまりクラス インスタンスへのポインターがあります。次のアプローチのうち、どれが最良だと思いますか? もっと違う方法でやりますか?

  1. unique_ptr<T>グローバル読み取り/書き込みロックと共にグローバルがあります。Foo()読み取り用にBar()ロックします。書き込みのためにロックしますInit()DeInit()
  2. セマフォを使用して、インスタンスを使用しているスレッドの数を追跡します。が呼び出された場合DeInit()、セマフォのカウントが 0 になるまで待機します。
  3. shared_ptrセマンティクスを使用します。グローバルshared_ptrは変更できますが、ユーザーがなくなるまでオブジェクトは削除されません。Init() は保留中の操作が完了するまで待機しない (そして待機する必要がない) ため、保留中の操作のニーズを満たす (多くのメモリを消費する) いくつかのインスタンスが存在する可能性があるため、システムが過負荷になる可能性があります。 .

オプション 3 は、C++11 を使用して実装するのが最も簡単なようです。私が間違っていたり、曖昧すぎる場合は、私を修正してください。

編集の明確化: Init() および DeInit() への呼び出しはグローバル ポインターを変更しているため、ロックによって同時に実行されないようにする必要があります。Foo() と Bar() は同時に実行できるはずです。

編集の明確化 C インターフェースとは、C インターフェースを実装する関数のセットを意味します。この一連の関数をスレッドセーフにしたい。

4

3 に答える 3

2

通常、グローバル変数を持つことは、非表示の変数であっても、可能であれば避けるべきです。クラスはすでにスレッド セーフであるため、ユーザーにハンドルを返すことでロックを完全に廃止します。彼らはそれについて何をすべきかを知るのに最適な立場にあります. 次に、適切なドキュメントを作成し、何をどのように同期するかをユーザーに決定させます。例えば:

void *handle = Init(...);
void *value = Foo(handle, ...);
int status = Bar(handle, ...);
DeInit(handle, ...);

ライブラリ ユーザー コードが C++ の場合、必要に応じて同期アクセスを使用してこれを C++ スマート ハンドラー クラスにラップするのは簡単です。ユーザーが何らかの方法で同時アクセスが発生しないことを知っている場合 (たとえば、ユーザー コードが単一のスレッドで実行される可能性がある場合)、何もロックする必要はありません。

[編集:タイプミス]

于 2013-08-24T13:06:14.530 に答える
0

あなたの質問を正しく理解していれば。

これを行うには、C++ クラスで静的ミューテックス/CS を使用して、外部スレッドが内部関数を同時に実行するのを停止します。

インターフェイスをスレッドセーフにする方法がわからないため、あなたの質問は私を混乱させます。インターフェイスがロジックを実行しない限り、実行されるコードに依存します。

インターフェイスがスレッド依存のロジックを実行している場合は、そのロジックをライブラリ側に移動することを検討する必要があります。これにより、コード内で他に何が起こっているかをより詳細に制御できます。

この回答があなたの質問とまったく関係がない場合は、事前にお詫び申し上げます。

于 2013-08-23T11:26:21.757 に答える
0

単一のグローバル変数が必要な場合の答えを次に示します。

//Lib.h

//extern "c" stuff

void Init(void);

type1 Foo(void);
type2 Bar(void);

void Deinit(void);


//Lib.cpp
#include "Lib.h"

// includes for mutex etc.

namespace {
    class RealObject{
    public:
        RealObject(){}
        type1 Foo();
        type2 Bar();
    };
    RealObject* getObject(){
        static RealObject obj;
        return &obj;
    }
    Mutex mutex;
}

void Init(void){
    Lock lock(mutex);
    getObject();
}

type1 Foo(void){
    return getObject()->Foo();
}
type2 Bar(void){
    return getObject()->Bar();
}

void Deinit(void){}

これは、すべてのクライアントが常にまたはInit()の組み合わせの前に呼び出すことを前提としていますFooBar

最初Init()はグローバルインスタンスを作成しDeinit()、nop です。

ミューテックスは、シングルトンを作成するためだけに存在します。

于 2013-08-23T15:24:43.700 に答える