grpc 服务中连接的简单线程安全向量

simple thread safe vector for connections in grpc service

我正在尝试了解并发性,我正在 grpc 服务中实现一个小型连接池,该服务需要与 postgres 数据库建立许多连接。

我正在尝试实现一个基本的 connectionPool 以防止为每个请求创建一个新连接。首先,我尝试创建一个线程安全 std::vector。当我 运行 grpc 服务器时,进行了单个事务,然后服务器阻塞,但我无法推断出发生了什么。任何帮助将不胜感激

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();
    }
};

在 main 中,然后我将 SafeVector* s = new SafeVector(4, 10); 传递到我的服务中 ServiceA(s)

里面ServiceA,我使用连接如下:

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

我到处放了一堆日志语句,我很确定我对 (1) shared_ptr 或 (2) 各种锁定结构的核心概念存在根本性的误解。

特别是,似乎在使用 4 个连接后(我机器上的最大硬件线程数),尝试 return [=] 中的连接时发生段错误(错误 11) 16=]方法。

如有任何帮助,我们将不胜感激。谢谢。

C++ 中的智能指针与对象所有权有关。

对象所有权是关于谁有权删除对象以及何时删除对象。

共享指针意味着谁可以删除以及何时删除是一个共同的问题。一旦说出"no one bit of code is permitted to delete this object",就无法收回

在您的代码中,您尝试获取一个具有共享所有权的对象并为您的 SafeVector 投降。这是不允许的。您无论如何都可以尝试调用 .get(),但删除该对象的权利仍归共享指针所有。

他们继续删除它(也许马上,也许明天)并且您的容器有一个指向已删除对象的悬空指针。


将您的共享点数更改为唯一点数。根据需要添加移动以使其编译。

投降,断言提供的唯一指针非空。

当你在里面的时候,

cv_.notify_one();

我也会

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

并更改:

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

如果您不更新 pool_ 的类型,而是将 .get() 更改为 .release()。与shared ptr不同,unique ptr可以放弃所有权。