2017-09-13 7 views
0

私は同時実行性について学びたいと思いますし、grpcサービスで小さな接続プールを実装しています。この接続プールはpostgresデータベースに多くの接続を行う必要があります。grpcサービスで接続するための単純なスレッドセーフなベクトル

私は基本的なconnectionPoolを実装して、リクエストごとに新しい接続を作成しないようにしています。まず、スレッドセーフstd::vectorを作成しようとしました。 grpcサーバーを実行すると、1つのトランザクションが作成され、サーバーがブロックされますが、何が起こっているのかを判断することはできません。私はの束を入れ

std::shared_ptr<pqxx::connection> c = safeVector_->borrow(); 
c->perform(SomeTransactorImpl); 
safeVector_->surrender(c); 

:すべてのヘルプは、次のように私は接続を使用し、私はその後、ServiceA(s)

ServiceAの内側に私のサービスにSafeVector* s = new SafeVector(4, 10);を通過し、メインで

class SafeVector { 
    std::vector<pqxx::connection*> pool_; 
    int size_; 
    int max_size_; 

    std::mutex m_; 
    std::condition_variable cv_; 
public: 
    SafeVector(int size, int max_size) : size_(size), max_size_(max_size) { 
     assert(size_ <= max_size_); 
     for (size_t i = 0; i < size; ++i) { 
      pool_.push_back(new pqxx::connection("some conn string")); 
     } 
    } 
    SafeVector(SafeVector const&)=delete; // to be implemented 
    SafeVector& operator=(SafeVector const&)=delete; // no assignment keeps things simple 

    std::shared_ptr<pqxx::connection> borrow() { 
     std::unique_lock<std::mutex> l(m_); 
     cv_.wait(l, [this]{ return !pool_.empty(); }); 
     std::shared_ptr<pqxx::connection> res(pool_.back()); 
     pool_.pop_back(); 
     return res; 
    } 

    void surrender(std::shared_ptr<pqxx::connection> connection) { 
     std::lock_guard<std::mutex> l(m_); 
     pool_.push_back(connection.get()); 
     cv_.notify_all(); 
    } 
}; 

をいただければ幸いです私は、(1)shared_ptrまたは(2)さまざまなロック構造のコアコンセプトの根本的な誤解を持っていると確信しています。

特に、4接続(私のマシン上のハードウェアスレッドの最大数)を使用した後、borrow()メソッドで接続を返そうとするとseg fault(エラー11)が発生するようです。

ご協力いただければ幸いです。ありがとう。

+1

'surrender()'は、生のポインタを 'pool_'に戻します。その後、 'connection'は範囲外になり、まったく同じオブジェクトを破壊します。 'pool_'は、ぶら下がっているポインタを保持してしまいます。おそらく 'pool_'を共有ポインタのベクトルで始めるのが最善でしょう。それとも、 'unique_ptr's:設計通り、クライアントがポインタを「降伏させる」というリスクを実行しますが、依然としてコピーを保持します。 @IgorTandetnikありがとう、 –

+0

それは非常に便利なウォークスルーです。 –

答えて

2

C++のスマートポインタは、オブジェクトの所有権に関するものです。

オブジェクトの所有権は、誰がオブジェクトを削除するかについてです。

共有ポインタとは、誰が削除されるのか、いつ共通の関心事があるのか​​を意味します。 「このオブジェクトを削除するコードは1つもない」と言ったら、取り戻すことはできません。

あなたのコードでは、共有された所有権を持つオブジェクトを取得し、あなたのSafeVectorが降伏したと主張します。これは許可されていません。とにかく.get()への呼び出しでそれを試みますが、そのオブジェクトを削除する権利は共有ポインタによって所有されたままです。

削除を進めると(すぐに、おそらく明日)、コンテナには削除されたオブジェクトへのぶら下がりのポインタがあります。


共有ptrsを一意のptrsに変更します。必要に応じて移動を追加してコンパイルします。

降伏したら、提供された固有のptrが空でないことをアサートします。

そして、あなたがそこにいるwhike、

cv_.notify_one(); 

私も

std::vector<std::unique_ptr<pqxx::connection>> pool_; 

とは変わってしまう:

pool_.push_back(std::move(connection)); 

をあなたはpool_の種類を更新しない場合は、代わりに.get().release()に変更してください。共有されたptrとは異なり、一意のptrは所有権を放棄することができます。

関連する問題