std::mutex lock 멤버 함수의 설명을 보면 lock을 호출한 함수에서 unlock을 호출하지 않은 상태에서 또 다시 lock을 호출하면 알 수 없는 동작을 한다고 되어 있습니다.

 

스레드에서 lock을 호출한 후 다시 lock을 호출하는 경우는 아래와 같은 경우입니다.

 

class buffer {

    list<int> queue;

    std::mutex mut;

public:

    bool empty() {

        std::lock_guard<std::mutex> lock(mut);

        return queue.empty();

    }

    ...

    int pop() throw(out_of_range) {

        std::lock_guard <std::mutex> lock(mut);

        while (empty())

        {   

……..

        }

        int tmp = queue.front();

        queue.pop_front();

        return tmp;

     }

};

코드 출처 : http://d.hatena.ne.jp/hidemon/20081218/1229555003

 


위의 buffer 클래스를 보면 pop() 함수를 호출하면 먼저 mutex로 락을 건 다음 empty() 함수를 호출하는데 empty도 같은 mutex를 사용하여 lock을 걸고 있습니다. 즉 이미 락을 건 mutex에 또 lock을 걸고 있습니다. 이런 경우 데드락 상황에 빠질 수가 있습니다. 이 문제를 풀기 위해서는 recursive_mutex를 사용합니다.

recursive_mutex는 같은 스레드에서 lock을 건 후 또 다시 lock을 걸어도 괜찮습니다. lock을 건 횟수만큼 꼭 unlock을 호출해야 합니다.

 

그럼 아래는 위의 buffer 클래스를 recursive_mutex를 사용하여 올바르게 수정한 것 입니다. 단순하게 std::mutex std::recursive_mutex로 바꾸면 됩니다.

(std::mutex std::recursive_mutex의 사용 방법은 같습니다)

 

class buffer {

    list<int> queue;

    std::recursive_mutex mut;

public:

    bool empty() {

        std::lock_guard<std::recursive_mutex> lock(mut);

        return queue.empty();

    }

    ...

    int pop() throw(out_of_range) {

        std::lock_guard <std::recursive_mutex> lock(mut);

        while (empty())

        {   

……..

        }

        int tmp = queue.front();

        queue.pop_front();

        return tmp;

     }

};

 

 

저작자 표시
신고
by 흥배 2013.07.01 08:00
| 1 |

티스토리 툴바