MongoDB C++: безопасен ли поток mongocxx::pool?

Нужно ли вручную блокировать mongocxx::pool при установлении соединения?

т.е. это безопасно? (пример скопирован с сайта Mongo)

mongocxx::instance instance{};
mongocxx::pool pool {mongocxx::uri{}};

using mongocxx::pool::entry = std::unique_ptr<client, std::function<void (client*)>>

auto threadfunc = [](mongocxx::client &client, stdx::string_view dbname) {
    client[dbname]["col"].insert({});
}
// don't even bother sharing clients. Just give each thread its own,
std::thread([]() {
    // pool.acquire() returns a mongo::pool::entry type
    mongocxx::client *c= pool.acquire().get();
    threadfunc(*c, "db1");
    threadfunc(*c, "db2");
});

std::thread([]() {
    mongocxx::client *c = pool.acquire().get();;
    threadfunc(*c, "db2");
    threadfunc(*c, "db1");
});

1 ответ

Решение

Да, mongocxx::pool потокобезопасен. Вы можете получить к нему доступ одновременно из нескольких потоков. Тем не менее, индивидуальный mongocxx::client объекты, возвращаемые из пула, не являются потокобезопасными, равно как и подчиненные объекты, такие как collection или же database полученный из client - вы не должны делиться ими между темами.

Также обратите внимание, что ваш пример (который не дословно скопирован с веб-сайта, но изменен из одного из примеров) содержит серьезную программную ошибку.

Эта строка:

   mongocxx::client *c= pool.acquire().get();

Получит запись пула, затем извлечет из нее пустой указатель. Однако запись пула будет уничтожена в конце оператора, что приведет к client объект должен быть возвращен в пул, что позволяет другому потоку потенциально забрать его, пока вы продолжаете его использовать.

Вы должны написать это как:

mongocxx::instance instance{};
mongocxx::pool pool {mongocxx::uri{}};

auto threadfunc = [](mongocxx::client &client, stdx::string_view dbname) {
    client[dbname]["col"].insert({});
}
// don't even bother sharing clients. Just give each thread its own,
std::thread([]() {
    // pool.acquire() returns a mongo::pool::entry type
    auto c = pool.acquire();
    threadfunc(*c, "db1");
    threadfunc(*c, "db2");
});

std::thread([]() {
    auto c = pool.acquire();
    threadfunc(*c, "db2");
    threadfunc(*c, "db1");
});

Таким образом, каждый поток сохраняет запись пула до тех пор, пока он не завершит ее использование, после чего она будет автоматически возвращена, когда unique_ptr в c уничтожен

Другие вопросы по тегам