Docs Menu
Docs Home
/ /

Seguridad de roscas y horquillas

Siempre debes darle a cada hilo su propio significado. mongocxx::client.

En general, cada mongocxx::client objeto y todos sus objetos mongocxx::client_session secundarios, mongocxx::database incluidos,, mongocxx::collection mongocxx::cursory, deben ser utilizados por un solo hilo a la vez. Esto se aplica incluso a los clientes adquiridos desde mongocxx::pool un.

Incluso si crea varios objetos secundarios a partir de un único client y los sincroniza individualmente, esto no es seguro, ya que modificarán simultáneamente las estructuras internas de client. Lo mismo ocurre si copia un objeto secundario.

mongocxx::instance instance{};
mongocxx::uri uri{};
mongocxx::client c{uri};
auto db1 = c["db1"];
auto db2 = c["db2"];
std::mutex db1_mtx{};
std::mutex db2_mtx{};
auto threadfunc = [](mongocxx::database& db, std::mutex& mtx) {
mtx.lock();
db["col"].insert_one({});
mtx.unlock();
};
// BAD! These two databases are individually synchronized, but they are derived from the same
// client, so they can only be accessed by one thread at a time
std::thread t1([&]() { threadfunc(db1, db1_mtx); threadfunc(db2, db2_mtx); });
std::thread t2([&]() { threadfunc(db2, db2_mtx); threadfunc(db1, db1_mtx); });
t1.join();
t2.join();

En el ejemplo anterior, aunque ambas bases de datos están sincronizadas individualmente, provienen del mismo cliente. Existe un estado compartido dentro de la biblioteca que ahora se modifica sin sincronización. El mismo problema ocurre si db2 es una copia de db1.

mongocxx::instance instance{};
mongocxx::uri uri{};
mongocxx::client c1{uri};
mongocxx::client c2{uri};
std::mutex c1_mtx{};
std::mutex c2_mtx{};
auto threadfunc = [](std::string dbname, mongocxx::client& client, std::mutex& mtx) {
mtx.lock();
client[dbname]["col"].insert_one({});
mtx.unlock();
};
// These two clients are individually synchronized, so it is safe to share them between
// threads.
std::thread t1([&]() { threadfunc("db1", c1, c1_mtx); threadfunc("db2", c2, c2_mtx); });
std::thread t2([&]() { threadfunc("db2", c2, c2_mtx); threadfunc("db1", c1, c1_mtx); });
t1.join();
t2.join();
mongocxx::instance instance{};
mongocxx::pool pool{mongocxx::uri{}};
auto threadfunc = [](mongocxx::client& client, std::string dbname) {
auto col = client[dbname]["col"].insert_one({});
};
// Great! Using the pool allows the clients to be synchronized while sharing only one
// background monitoring thread.
std::thread t1 ([&]() {
auto c = pool.acquire();
threadfunc(*c, "db1");
threadfunc(*c, "db2");
});
std::thread t2 ([&]() {
auto c = pool.acquire();
threadfunc(*c, "db2");
threadfunc(*c, "db1");
});
t1.join();
t2.join();

En la mayoría de los programas, los clientes tienen una larga vida útil por comodidad y rendimiento. En este ejemplo artificial, hay bastantes gastos generales porque trabajamos muy poco con cada cliente, pero normalmente es la mejor solución.

Ni un mongocxx::client ni un mongocxx::pool se pueden copiar de forma segura durante la bifurcación. Por ello, cualquier cliente o grupo debe crearse después de la bifurcación, no antes.

Volver

Configuración e instalación avanzadas

En esta página