2016-04-04 6 views
3

私はC APIの「スレッドセーフな」C++ラッパーを作成していますが、API自体はスレッドセーフではありません。私はRAIIを使用しようとしました。C APIのスレッドセーフなC++ラッパーを書く努力

私が知りたいのは、私の実装は正しいのですか?スレッドセーフであるかどうか。私は自分のコードに関するコメントを感謝します。前もって感謝します!

次のようにラップするC APIがあり、

/* an data structure which represents a connection proxy to the logger: */ 
struct cLog_Logger; 

/* connect the logger, and returns a handle to it: */ 
cLog_Logger* cLog_connect(); 

/* appends a zero terminated string to the log: */ 
void cLog_write(cLog_Logger* logger, const char* message); 

/* closes the connection with the logger: */ 
void cLog_close(cLog_Logger* logger); 

次のようにラッパーの私の実装は次のとおりです。

class LoggerWrapper{ 

    public: 
     LoggerWrapper(){    //constructor 
      cLog= cLog_connect(); 
     } 

     void log(const std::string &message){ //entry point 
      cLog_write(cLog, message); 
      cLog_close(cLog); 
      } 

     ~LoggerWrapper(){  //destructor 
      delete cLog; 
     } 
    protected: 
     cLog_Logger *cLog; 
} 

ありがとう!

+0

スレッドはどこですか? – Ajay

+0

@Ajay、スレッドはラッパーの外のどこにでもあります:) – user2807083

答えて

3

私はあなたがこのような実装に変更する必要があると思う:

class LoggerWrapper{ 

public: 
    LoggerWrapper(){    //constructor 
     cLog= cLog_connect(); 
    } 

    void log(const std::string &message){ //entry point 
     cLog_write(cLog, message); 
     } 

    ~LoggerWrapper(){  //destructor 
     cLog_close(cLog); 
     delete cLog; 
    } 
protected: 
    cLog_Logger *cLog; 
} ; 

これは、あなたがこのようなコードを記述することができます:

LoggerWrapper logger ; 
logger.log("Something") ; 
logger.log("Something else) ; 

ので、同じオブジェクトを持つ複数のログを作成します。さもなければ、最初の呼び出しはロガーを閉じ、オブジェクトは役に立たない。これは、あなたの望むことですか?

次に、2番目の質問があります。スレッドの安全性はどういう意味ですか?別のスレッドから同じオブジェクトにログを作成しますか?

class LoggerWrapper{ 

public: 
    LoggerWrapper(){    //constructor 
     cLog= cLog_connect(); 
    } 

    void log(const std::string &message){ //entry point 
     std::lock_guard<std::mutex> guard(mutex); 
     cLog_write(cLog, message); 
     } 

    ~LoggerWrapper(){  //destructor 
     cLog_close(cLog); 
     delete cLog; 
    } 
protected: 
    cLog_Logger *cLog; 
    std::mutex mutex ; 
} ; 
+0

私は、静的でないクラスメンバーとしてのmutexは問題を解決するとは思いません。 2つの異なるスレッドに2つのLoggerWrapperインスタンスを作成することを想像してみてください。ブーム! – user2807083

+0

@marom、 'cLog_close(cLog)'をデストラクタに移動すると良い点ですが、ログ書き込みが終わるとすぐに接続を終了することを考慮しましたが、それは意味があるかどうかはわかりません。 – ulyssis2

+0

@marom、 "スレッドの安全性"に関するあなたの推測は正しいですが、APIには同期の問題を回避する仕組みがありません。あなたの解決策は正しいようですが、多くの感謝!感謝! – ulyssis2

2

短い答え:いいえ、それはありません

次に、あなたは、このように対数関数の内部でミューテックスロックガードを追加することができます。最初はdeleteの代わりにfree()がなければならないと思います。なぜなら、それはc apiだからです。 あなたがやっていることはあなたのリソースリークフリープログラムを与えることができますが、スレッドセーフではありません。 RAIIは、リソースのリークを回避するためのものです。 RAIIクラスに静的なmutexを追加するスレッドセーフなAPIをラップするのは簡単ですが非効率的な方法です。

#include <mutex> 

class LoggerWrapper{ 

public: 
    LoggerWrapper() : l(globalLock); 
    {    //constructor 
     cLog= cLog_connect(); 
    } 

    void log(const std::string &message){ //entry point 
     cLog_write(cLog, message); 
     cLog_close(cLog); 
     } 

    ~LoggerWrapper(){  //destructor 
     free(cLog); // I think here must be free(), but not sure 
    } 
protected: 
    cLog_Logger *cLog; 
    static std::mutex globalLock; 
    std::lock_guard<std::mutex> l; 
} 

std::mutex LoggerWrapper::globalLock; 
+0

ありがとう!私たちはC++ラッパークラスについて議論しているので、ree()とdeleteは大きな違いをもたらさないと思います。 – ulyssis2

+0

lock_guardメンバーの使用方法を教えてください。メンバ 'l'は初期化時に割り当てられますが、後で何もしません。 – ulyssis2

+0

@ ulyssis2、lock_guardは、コンストラクタでmutexロックを取得し、そのデストラクタでmutexロックを解放するRAIIテンプレートです。 lock_guardが存在する間、mutexはロックされた状態で保持されます。 – user2807083