C++에서 스레드 안에 스레드 넣을 수 있나요?

조회수 1766회

스레드 안에 스레드를 넣을 수 있을까요?

지금 파이썬은 스레드 안에 스레드 넣으면 (밖의 스레드를 A 스레드 안의 스레드를 B라고 하면)

AB / AB / AB / AB... 이런 식으로 반복이 되거든요 (A와 B스레드 모두 안에 while True 무한루프 있음)

근데 C++은 스레드 안에 스레드를 넣어봤는데

ABBBBBBBBBBBBBBBBBBBBBBB.... 이렇게 출력 됩니다. 즉, 처음 스레드는 한 번만 되고 스레드 안의 스레드만 무한 반복 되는 꼴이라는건데요.

파이썬 처럼 AB / AB / AB / AB... 이렇게 반복 되게는 할 수 없을까요?

스레드 안의 스레드를 detach로 하더라도 AAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.... 이렇게 나오더라구요.

가장 좋은 경우는 A 따로, B따로 무한루프를 돌게 하는 건데.. 문제는 main에서 바로 스레드를 돌리지 못 합니다.

지금 굳이 왜 A안에 B를 넣었느냐면, A에서 다른 클라이언트로부터 받은 정보가 전달인자로 들어가 B의 스레드가 실행되어야 하는 상황입니다. (A는 항상 recv가 가능한 Server 코드입니다.)

1 답변

  • 좋아요

    1

    싫어요
    채택 취소하기

    fiber와 같은 특수 상황이 아닌 이상, 쓰레드 안 쓰레드란 개념은 없습니다.

    아래 처럼 한 쓰레드의 스택 내 변수에 다른 쓰래드의 핸들이 존재한다는 의미로 생각 됩니다. 이를 쓰레드 안 쓰레드라고 부르지 않습니다.

    void funcB() {
        while (true){
            // ...
        }
    }
    void funcA() {
        std::thread b(funcB);
        b.detach();
        while (true){
            // ...
        }
    }
    int main() {
        std::thread a(funcA);
        a.join();
        return 0;
    }
    

    ABBBBBBBBBBBBBBBBBBBBBBB.... 이렇게 출력 됩니다. 즉, 처음 스레드는 한 번만 되고 스레드 안의 스레드만 무한 반복 되는 꼴이라는건데요.

    OS에서 동작하는 모든 응용 프로그램의 쓰레드는 OS에 의해 스케줄링됩니다. 어떤 쓰레드가 어느 코어에서 얼마만큼의 시간을 할당받아 동작할 지는 OS가 결정하게 됩니다. 이는 C++던 Python 이던 모두 동일합니다.

    ABBBBBBBBBBBBBBBBBBBBBBB 와 같이 동작한다고 한다면 이는 OS가 아직 쓰레드 A를 실행해야한다고 결정하지 않았기 때문입니다. OS는 왜 그런 판단을 하였냐고 한다면, 쓰레드의 스케줄링은 while 루프 한번을 기준으로 이루어지는 것이 아니기 때문입니다.

    기존적인 방법으로 일정 시간 단위(time quantum)로 각각의 쓰레드를 돌아가면서 실행을 하게 됩니다. 만약 이 시간단위가 1ms이라서 쓰레드 A와 B가 1ms 씩 CPU를 사용할 시간을 할당 받아 동작하는데, while 루프 한번 도는데 걸리는 시간이 0.0001ms 라면 쓰레드 B가 1000번 루프를 돌고 쓰레드 A가 동작할 것입니다.

    두 쓰레드가 경쟁상태가 아닌 이상 한 쓰레드가 일방적으로 동작하지는 않습니다.

    파이썬 처럼 AB / AB / AB / AB... 이렇게 반복 되게는 할 수 없을까요?

    OS는 쓰레드를 루프 한번 기준으로 돌아가며 동작 시키는 것이 아니기에 "다른 쓰레드를 동작 시켜줘" 라고 알려줄 필요가 있습니다.

    이는 OS에게 CPU사용을 다했으니 다른 쓰레드에게 양보하겠다는 의미입니다. 이 함수가 호출되면 OS는 아직 다른 쓰레드로 전환할 시간이 아니지만 현재 쓰레드의 실행을 중지하고 다른 쓰레드를 실행합니다.

    하지만 yield()를 호출 한다고해서 OS가 반드시 이를 따르는 것은 아니기에 정확히 AB/AB/AB 순으로 동작하지는 않습니다.

    condition_variable는 쓰레드간 흐름 동기를 맞추기 위해서 사용합니다. 이 것이 제공하는 기능중에 알림 기능이 있습니다.

    아래 코드와 같이 사용할 수 있으나, 이는 두 쓰레드가 번갈아가면서 실행되기 때문에 한 쓰레드는 다른 쓰레드의 완료를 기다리게 됩니다.

    std::mutex mutex;
    std::condition_variable cv;
    bool flag = true;
    void funcB() {
        while (true) {
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, []() { return !flag; });
            // ...
            flag = true;
            lock.unlock();
            cv.notify_one();
        }
    }
    void funcA() {
        std::thread b(funcB);
        b.detach();
        while (true){
            std::unique_lock<std::mutex> lock(mutex);
            cv.wait(lock, []() { return flag; });
            // ...
            flag = false;
            lock.unlock();
            cv.notify_one();
        }
    }
    int main() {
        std::thread a(funcA);
        a.join();
        return 0;
    }
    

    추가로 Python 에서는 AB / AB / AB / AB... 으로 동작했는지를 추측해보면 GIL 때문이 아닐까 생각합니다.

    • 이책 저책 다 찾아 보고 있는데, 책에서 볼 수 없는 개념을 알게 해 주셔서 감사합니다. 반시 2020.4.22 09:18

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)