이 페이지에서

재진입 가능성과 스레드 안전성

이 문서 전반에 걸쳐 ‘재진입 가능 ( reentrant )’ 및 ‘스레드 안전(thread-safe) ’이라는 용어는 클래스와 함수가 멀티스레드 애플리케이션에서 어떻게 사용될 수 있는지를 나타내기 위해 사용됩니다:

  • 스레드 안전 함수는 공유 데이터에 대한 모든 참조가 순차적으로 처리되므로, 호출 시 공유 데이터를 사용하더라도 여러 스레드에서 동시에 호출될 수 있습니다.
  • 재진입 가능한 함수도 여러 스레드에서 동시에 호출될 수 있지만, 각 호출이 자체 데이터를 사용하는 경우에만 가능합니다.

따라서 스레드 안전 함수는 항상 재입력 가능하지만, 재입력 가능한 함수가 항상 스레드 안전하지는 않습니다.

더 나아가, 각 스레드가 서로 다른 클래스 인스턴스를 사용하는 한, 클래스의 멤버 함수를 여러 스레드에서 안전하게 호출할 수 있다면 해당 클래스는 재진입 가능하다고 합니다. 모든 스레드가 동일한 클래스 인스턴스를 사용하더라도 멤버 함수를 여러 스레드에서 안전하게 호출할 수 있다면, 해당 클래스는 스레드 안전합니다.

참고: Qt 클래스는 여러 스레드에서 사용하도록 의도된 경우에만 스레드 안전하다고 문서화됩니다. 함수가 스레드 안전하거나 재진입 가능으로 표시되지 않은 경우, 서로 다른 스레드에서 해당 함수를 사용해서는 안 됩니다. 클래스가 스레드 안전(thread-safe)이나 재진입 가능(reentrant)으로 표시되지 않은 경우, 해당 클래스의 특정 인스턴스에 다른 스레드에서 접근해서는 안 됩니다.

재진입성

C++ 클래스는 단순히 자체 멤버 데이터에만 접근하기 때문에 종종 재진입 가능합니다. 다른 스레드가 동시에 해당 클래스의 동일한 인스턴스에 대해 멤버 함수를 호출할 수만 없다면, 어떤 스레드든 재진입 가능한 클래스의 인스턴스에 대해 멤버 함수를 호출할 수 있습니다. 예를 들어, 아래의 ` Counter ` 클래스는 재진입 가능합니다:

class Counter
{
public:
    Counter() { n = 0; }

    void increment() { ++n; }
    void decrement() { --n; }
    int value() const { return n; }

private:
    int n;
};

이 클래스는 스레드 안전하지 않습니다. 여러 스레드가 데이터 멤버 ` n`를 수정하려고 시도하면 결과가 정의되지 않기 때문입니다. 이는 ` ++ ` 및 ` -- ` 연산자가 항상 원자적이지 않기 때문입니다. 실제로 이 연산자들은 대개 다음 세 가지 기계어 명령어로 확장됩니다:

  1. 변수의 값을 레지스터에 로드합니다.
  2. 레지스터의 값을 증가시키거나 감소시킵니다.
  3. 레지스터의 값을 메인 메모리에 다시 저장합니다.

스레드 A와 스레드 B가 동시에 변수의 이전 값을 로드하고, 각자의 레지스터 값을 증가 또는 감소시킨 뒤 다시 저장하면, 서로의 값을 덮어쓰게 되어 변수의 값은 단 한 번만 증가하게 됩니다!

스레드 안전성

분명히, 액세스는 순차적으로 이루어져야 합니다. 스레드 A가 1, 2, 3단계를 중단 없이(원자적으로) 수행한 후에야 스레드 B가 동일한 단계를 수행할 수 있어야 하며, 그 반대의 경우도 마찬가지입니다. 클래스를 스레드 안전하게 만드는 쉬운 방법은 데이터 멤버에 대한 모든 액세스를 ` QMutex`로 보호하는 것입니다:

class Counter
{
public:
    Counter() { n = 0; }

    void increment() { QMutexLocker locker(&mutex); ++n; }
    void decrement() { QMutexLocker locker(&mutex); --n; }
    int value() const { QMutexLocker locker(&mutex); return n; }

private:
    mutable QMutex mutex;
    int n;
};

QMutexLocker 클래스는 생성자에서 자동으로 뮤텍스를 잠그고, 함수 끝에서 소멸자가 호출될 때 잠금을 해제합니다. 뮤텍스를 잠그면 서로 다른 스레드 간의 액세스가 순차적으로 처리됩니다. mutex 데이터 멤버는 const 함수인 value() 내에서 뮤텍스를 잠그고 해제해야 하므로, mutable 한정자와 함께 선언됩니다.

Qt 클래스에 대한 참고 사항

많은 Qt 클래스는 재진입 가능하지만, 스레드 안전하게 설계되지는 않았습니다. 스레드 안전하게 만들 경우 QMutex 를 반복적으로 잠그고 해제하는 데 추가적인 오버헤드가 발생하기 때문입니다. 예를 들어, QString 는 재진입 가능하지만 스레드 안전하지는 않습니다. 여러 스레드에서 동시에 서로 다른 QString 인스턴스에 안전하게 접근할 수 있지만, 여러 스레드에서 동시에 동일한 QString 인스턴스에 안전하게 접근할 수는 없습니다( QMutex 를 사용하여 직접 접근을 보호하는 경우는 예외입니다).

일부 Qt 클래스와 함수는 스레드 안전합니다. 주로 스레드 관련 클래스(예: QMutex)와 기본 함수(예: QCoreApplication::postEvent())가 이에 해당합니다.

참고: 멀티스레딩 분야의용어는 완전히 표준화되어 있지 않습니다. POSIX는 C API에서 재진입 가능(reentrant) 및 스레드 안전(thread-safe)에 대해 다소 다른 정의를 사용합니다. Qt와 함께 다른 객체 지향 C++ 클래스 라이브러리를 사용할 때는 해당 정의들을 정확히 이해하고 있는지 확인하십시오.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.