Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
Docs Menu
Docs Home
/ /

Seguridad frente a subprocesos y bifurcaciones

Siempre debes darle a cada hilo su propio 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 las dos bases de datos estén sincronizadas individualmente, se derivan del mismo cliente. Hay un estado compartido dentro de la librería que ahora está siendo modificado 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 estarán activos por conveniencia y rendimiento. En este ejemplo fabricado, hay bastantes gastos en general porque hacemos muy poco trabajo con cada cliente, pero normalmente esta es la mejor solución.

Ni un mongocxx::client ni un mongocxx::pool se pueden copiar de forma segura al hacer un fork. Debido a esto, cualquier cliente o pool debe crearse después de realizar el fork, no antes.

Volver

Almacene archivos grandes

En esta página