Docs Menu
Docs Home
/ / /
C++ 드라이버

스레드 및 포크 안전성

이 페이지의 내용

  • 잘못된 스레딩 예시
  • 허용되는 스레딩 예제
  • 이상적인 스레딩 예제
  • 포크 세이프티

항상 각 스레드에 고유한 mongocxx::client 을(를) 부여해야 합니다.

일반적으로 각 mongocxx::client 객체와 mongocxx::client_session, mongocxx::database, mongocxx::collectionmongocxx::cursor 을(를) 포함한 모든 하위 객체 는 한 번에 단일 스레드에서 사용해야 합니다. 이는 mongocxx::pool 에서 획득한 클라이언트의 경우에도 마찬가지입니다.

단일 client 에서 여러 하위 객체를 생성하고 개별적으로 동기화하더라도 client 의 내부 구조를 동시에 수정하므로 안전하지 않습니다. 자식 객체를 복사하는 경우에도 마찬가지입니다.

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

위의 예에서는 두 데이터베이스가 개별적으로 동기화되어 있더라도 동일한 클라이언트에서 파생됩니다. 라이브러리 내부에 현재 동기화 없이 수정 중인 공유 상태가 있습니다. db2db1 의 복사본인 경우에도 동일한 문제가 발생합니다.

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

대부분의 프로그램에서 클라이언트는 편의성과 성능면에서 오래 지속됩니다. 이 간단한 예에서는 각 클라이언트에 대한 작업을 거의 수행하지 않기 때문에 상당한 오버헤드가 있지만 일반적으로 이것이 최상의 솔루션입니다.

포크 시 mongocxx::client 또는 mongocxx::pool 모두 안전하게 복사할 수 없습니다. 이 때문에 모든 클라이언트 또는 풀은 이전이 아닌 포크 이후 에 생성되어야 합니다.

돌아가기

고급 구성 및 설치