[개요]
C++로 작성된 회사 프로젝트에서 Onvif를 연동한 소스코드가 있는데, profileMutex, streamMutex 등의 뮤텍스를 사용하여 PTZ와 Onvif SDK를 사용하였다.
위의 각 PTZ 함수들이 모두 profileMutex를 잠근 후 사용하고 있는데, 문제는 뮤텍스를 사용하는 함수에서 또 뮤텍스를 사용하는 다른 함수를 호출하는 경우가 존재한다.
위 함수는 SetPreset() 함수인데, 처음에 profileMutex를 잠근 후에 아래에서 RemovePreset()을 호출하고, 다음에는 GetPresets()를 호출하고 있다.
이 코드는 그나마 리팩토링이 되어서 이중락이 발생하지 않도록 수정되었으나, 다른 함수들에서도 이런 경우가 발생할 여지가 높아보이도록 코드가 작성되었다.
[개선방안]
mutex_manager라는 클래스를 생성하고 멤버함수를 통해 락을 취할 수 있도록 하였다. 이때, 락이 이미 잠겨있는 상태 (다른 스레드가 사용중인 경우) 일 때, 사용중인 스레드가 현재 요청한 스레드와 동일한 경우, 락 요청을 무시하고, 다른 스레드가 락을 요청한 경우 기존 스레드가 작업을 끝날 때 까지 대기하도록 하여 이중락 문제를 개선하였다.
class mutex_manager {
public:
mutex_manager(const int & channelIndex):
channelIndex(channelIndex),
deviceAddr("0.0.0.0") {}
mutex_manager(const int & channelIndex,
const std::string & deviceAddr):
channelIndex(channelIndex),
deviceAddr(deviceAddr) {}
//INFO: 같은 스레드에서 잠금 시도시 무시하고, 다른 스레드에서 잠금 시도 시 대기
void get_mutex_lock(boost::mutex::scoped_try_lock & locker) {
const boost::thread::id & currThreadId = boost::this_thread::get_id();
boost::mutex::scoped_try_lock tempLock(mtx);
//INFO: 뮤텍스 획득 실패
if (!tempLock.owns_lock()) {
//INFO: 같은 스레드에서 뮤텍스를 이미 사용중인 경우 무시
if (mtxIndex == currThreadId) {
InnoLogWarn("[%s] %s; channelIndex=%d. this thread already has profileMutex lock", deviceAddr.c_str(), __func__, channelIndex);
return;
}
//INFO: 다른 스레드에서 요청한 경우 대기
//InnoLogTrace("[%s] %s; other thread has lock. wait.", deviceAddr.c_str(), __func__);
tempLock.lock();
}
mtxIndex = currThreadId;
tempLock.swap(locker);
}
private:
//INFO: 이 뮤텍스는 get_profile_mutex_lock() 함수를 통해서만 사용할 것
boost::mutex mtx;
//INFO: profileMutex를 현재 사용중인 스레드 ID를 보관
boost::thread::id mtxIndex;
//INFO: 채널 인덱스
int channelIndex;
//INFO: IP주소
std::string deviceAddr;
};
기존 코드에서는 뮤텍스의 락을 할 때 다음과 같이 블록을 만든 후 boost::mutex::scoped_lock을 선언하여 사용하였다.
개선방안에서는 뮤텍스를 직접 잠그는 것이 아니라 get_mutex_lock() 멤버함수를 호출하고, 만약 해당 뮤텍스가 잠겨있지 않다면 새로운 locker를 만들고 파라미터로 받은 locker로 넘겨준다. 이미 잠겨있다면 현재 사용중인 스레드를 검사하는데, 그 스레드가 현재 요청한 스레드와 같다면 이중락을 막기 위해 그대로 return하고, 다른 스레드라면 이전 스레드가 처리를 끝낼 때 까지 대기하게 된다.
이로써, 같은 스레드에서 같은 뮤텍스를 여러번 호출하여 이중락이 발생하는 문제를 막을 수 있게 된다.
'컴퓨터 공학 > C++' 카테고리의 다른 글
윈도우 10 + Visual Studio 2017에서 C++ Boost 1.59.0 버전 설치하기 (0) | 2021.02.23 |
---|---|
[C++] MSVC++ v14.26와 Mingw-w64 v8.1.0의 성능 측정 (0) | 2020.07.13 |
Boost 기반 뮤텍스 안전하게 사용하도록 하는 코드 (0) | 2020.06.24 |
C++ 멀티바이트 문자열을 UTF-8로 변경하는 함수 (0) | 2020.06.08 |
C++ Printf 검사 프로그램 (0) | 2020.02.24 |