2016-07-18 11 views
3

recursive_mutex이 들어있는 unique_lock을 이동할 때 어떤 일이 발생하는지 궁금합니다.unique_lock <recursive_mutex>를 다른 스레드로 이동

특히,이 코드를 찾고 있었어요 :

recursive_mutex g_mutex; 

#define TRACE(msg) trace(__FUNCTION__, msg) 

void trace(const char* function, const char* message) 
{ 
    cout << std::this_thread::get_id() << "\t" << function << "\t" << message << endl; 
} 

future<void> foo() 
{ 
    unique_lock<recursive_mutex> lock(g_mutex); 
    TRACE("Owns lock"); 
    auto f = std::async(launch::async, [lock = move(lock)]{ 
     TRACE("Entry"); 
     TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Owns lock! 
     this_thread::sleep_for(chrono::seconds(3)); 
    }); 
    TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!"); // Prints Doesn't own lock! 
    return f; 
} 


int main() 
{ 
    unique_lock<recursive_mutex> lock(g_mutex); 
    TRACE("Owns lock"); 
    auto f = foo();  
    TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!");  // Prints Owns lock! 
    f.wait(); 
    TRACE(lock.owns_lock()? "Owns lock!" : "Doesn't own lock!");  // Prints Owns lock! 
} 

이 샘플 코드의 출력은 나에게 많은 놀라게했다. main()의 unique_lock은 스레드가 뮤텍스를 릴리스했다는 것을 어떻게 알 수 있습니까? 진짜야?

+3

당신이 뭘 놀라워하는지 명확하지 않습니다. 'own__lock()'이 리턴하는'unique_lock'에 간단한 부울 멤버가 있습니다.이 멤버는 이동 생성자에 의해 예측 가능하고 문서화 된 방식으로 이동됩니다. 'owns_lock()'은 기본 뮤텍스를 건드리지 않습니다. 당신의 프로그램은 정의되지 않은 행동을 보입니다 : 유니크 락이 worker 쓰레드에서 파괴되면'g_mutex.unlock()'을 호출하지만 worker 쓰레드는'g_mutex' 'unlock()'에 대한 필요 조건). –

+0

@IgorTandetnik 감사합니다. 그래서 쓰레드간에'recursive_mutex '의 소유권을 옮기는 것은 불가능합니까? 뮤텍스가 재귀 적이 아닌 경우 'unique_lock'을 움직이면 소유권을 소유자 스레드로 옮길 수 있습니까? –

+3

스레드간에'unique_lock'을 이동하는 것은 전혀 도움이되지 않습니다. 'unique_lock'은'뮤텍스 *'포인터와'bool owns' 플래그에 불과하다는 것을 알 수 있습니다 - 검은 마법은 없습니다. 이동 생성자는 단순히 포인터와 부울을 이동합니다. my_mutex.lock()을 호출 한 스레드와 다른 스레드에서'my_mutex.unlock()'을 호출하면 명시 적으로 또는 간접적으로'unique_lock'을 속여서 수행하는 것과 같이 정의되지 않은 동작을 보입니다. 이것은 모든 뮤텍스의 특징입니다. –

답변

3

일부 마법 속성은 unique_lock으로 간주됩니다. 어떤 것도없고, 아주 간단한 수업입니다. 여기에는 Mutex* pmbool owns의 두 데이터 멤버가 있습니다 (설명을위한 멤버 이름 만 표시). lock()은 단순히 pm->lock(); owns = true;이고 unlockpm->unlock(); owns = false;입니다. 소멸자는 if (owns) unlock();입니다. 두 멤버를 통해 생성자 복사본을 이동하고 원래대로 nullptrfalse으로 설정합니다. owns_lock()owns 구성원의 값을 리턴합니다.

모든 스레드 동기화 마법은 뮤텍스 자체에 있으며 lock()unlock() 메쏘드입니다. unique_lock은 그 주위의 단순한 래퍼 일뿐입니다.

mutex.unlock()을 호출하는 스레드는 전제 조건으로 뮤텍스 (이전에 해당 스레드가 lock()을 호출했음을 의미)를 보유해야합니다. 그렇지 않으면 프로그램에서 정의되지 않은 동작을 보입니다. unlock을 명시 적으로 호출하든 unique_lock과 같은 도우미를 속여 전화를하든 사실입니다.

이 모든 측면에서 unique_lock 인스턴스를 다른 스레드로 옮기는 것은 잠시 후 정의되지 않은 동작을 트리거하는 방법 일뿐입니다. 거꾸로도 없다.