8


3

ライブラリの初期化とシャットダウンの一般的なパターンは?

基礎となる(C)ライブラリの必要な初期化およびクリーンアップルーチンを呼び出すために使用できるパターンはありますか? 私の場合、ラッパークラスを作成して、他のオブジェクトに合成できるようにします。 問題は、ラッパークラスを破棄すると、基になるライブラリのクリーンアップルーチンが呼び出されることです。 ラッパークラスの複数のオブジェクトをインスタンス化するまでは問題ありません。 私の質問は、この状況を実際に処理するための_最善の方法は何ですか? 静的な参照カウンターが思い浮かびますが、他の潜在的に優れたオプションと関連する取引があるかどうかを知りたかったのです。

5 Answer


4


すべてがクラスである必要はありません。 シングルトンパターンを使用すると、これをクラスに変えることができますが、実際にはグローバル関数で何かを購入するわけではありません。

bool my_library_init();
void my_library_shutdown();

ライブラリが正常に初期化された場合、最初の呼び出しはtrueを返し、2番目の呼び出しは実行する必要があるものを何でも静かに実行して終了します。 これらのインターフェイスの背後に、参照カウントやスレッドトラッキングタイプのものを自由に追加できます。

また、ライブラリがこのすべてを透過的に実行できる可能性を無視しないでください。 最初のライブラリ関数が呼び出されたときに、まだ初期化されていないことを検出し、作業を行う前にすべてを設定できますか? シャットダウンの場合、破棄するリソースをグローバルオブジェクトに登録するだけで、プログラムの終了時に破棄されます。 この方法で行うのは確かに難しいですが、ライブラリの呼び出し元にとって使いやすさのメリットに値する場合があります。


2


mainが開始する前に初期化を呼び出し、mainが終了した後にクリーンアップを呼び出すことができる場合、この小さなトリック(ハック?)が役に立つかもしれません:

#include

// C library initialization routine
void init() {std::cout << "init\n";}

// C library cleanup routine
void fini() {std::cout << "fini\n";}

// Put this in only one of your *.cpp files
namespace // anonymous
{
    struct Cleaner
    {
        Cleaner() {init();}
        ~Cleaner() {fini();}
    };
    Cleaner cleaner;
};

int main()
{
    std::cout << "using library\n";
}

出力:

init
using library
fini

静的オブジェクトのコンストラクタはmainの前に呼び出され、デストラクタはmainの後に呼び出されるという事実を(悪用?)使用します。 プログラム全体のRAIIのようなものです。


1


私は多くの「シングルトン」の話を見てきましたので、http://loki-lib.cvs.sourceforge.net/loki-lib/loki/include/loki/Singleton.h?view = markupを見てお勧めします[アレクサンドレスクの仕事]。

しかし、そこに「シングルトン」が本当に必要かどうかはわかりません。 あなたがそうするなら、あなたはあなたのすべての呼び出しが状態を共有しようとしているので…​ そうですか? 最後の呼び出しで設定された状態を取得するために、 `Wrapper`の別のインスタンスを介してライブラリを呼び出すとき、本当に望みますか?

そうでない場合は、アクセスをシリアル化し、毎回データを再初期化する必要があります。

class Wrapper
{
public:
  Wrapper() { lock(Mutex()); do_init_c_library(); }
  ~Wrapper() { do_clean_up_c_library(); unlock(Mutex()); }

private:
  static Mutex& Mutex() { static Mutex MMutex; return MMutex; }
}; // class Wrapper

とても簡単です…​ ただし、「Mutex」が正しく(1回)初期化され、それが不要になるまで有効にする必要があります。

`Boost`はhttp://www.boost.org/doc/libs/1_42_0/doc/html/thread/synchronization.html#thread.synchronization.once[1回発行]の機能を提供します。 「MMutex」でのアプローチは、うまくいかないはずです…​ (ハム)と思います。


0


ライブラリの実装を変更できる場合は、ライブラリの関数の1つを呼び出すたびに、最初の使用時に作成されるシングルトンにアクセスできます。

または、グローバル変数または静的変数をライブラリに配置します。ライブラリは、構築中に初期化し、破棄中にシャットダウンします。 (ライブラリがグローバル変数自体を使用し、初期化/シャットダウンの順序がそれらと競合する場合、それは迷惑になるかもしれません。 また、リンカは、参照されていないグローバルを削除することを決定するかもしれません…​)

それ以外の場合、参照カウントを回避する方法がわかりません。 (ただし、プログラムの有効期間中に複数の初期化/シャットダウンサイクルを作成する可能性があるという欠点があることに注意してください。)


0


Cライブラリルーチンのセットが大きすぎない場合は、http://en.wikipedia.org/wiki/Singleton_pattern [Singleton]とhttp://en.wikipedia.org/wiki/Facade_pattern[Facade]を組み合わせてみてください。 Cライブラリルーチンがファサードを介してのみ呼び出されるようにするパターン。 Facadeは、Cライブラリの初期化とクリーンアップを保証します。 シングルトンは、ファサードのインスタンスが1つだけであることを保証します。

#include

// C library initialization and cleanup routines
void init() {std::cout << "init\n";}
void fini() {std::cout << "fini\n";}

// C library routines
void foo() {std::cout << "foo\n";}
void bar() {std::cout << "bar\n";}


class Facade // Singleton
{
public:
    void foo() {::foo();}
    void bar() {::bar();}
    static Facade& instance() {static Facade instance; return instance;}

private:
    Facade() {init();}
    ~Facade() {fini();}
};

// Shorthand for Facade::instance()
inline Facade& facade() {return Facade::instance();}


int main()
{
    facade().foo();
    facade().bar();
}

出力:

init
foo
bar
fini