티스토리 뷰
데드락 현상은
예를 들어 스레드 Process1 그리고 Process2 가 존재하고
서로 자원(Resource)을 점유하고있고
P1 -> P2(점유하고있는 자원)
P2 -> P1(점유하고있는 자원)
접근할때 데드락 현상이 일어난다.
서로 점유하고있는 자원에 LOCK을 걸고있고 풀지않으니깐 일어나는 현상이다.
그러면 데드락현상을 한번 생성해보자.
#include <iostream>
#include <algorithm>
#include <thread>
#include <atomic>
#include <mutex>
#include "ItemRepository.h"
#include "UserRepository.h"
using namespace std;
ItemRepository itemRepository;
UserRepository userRepository;
void Func1()
{
for (int i = 0; i < 1000; i++) {
userRepository.saveUser(&itemRepository);
}
}
void Func2()
{
for (int i = 0; i < 1000; i++) {
itemRepository.saveItem(&userRepository);
}
}
int main()
{
std::thread t1;
std::thread t2;
t1 = std::thread(Func1);
t2 = std::thread(Func2);
t1.join();
t2.join();
cout << "Job Done" << endl;
return 0;
}
UserRepository 클래스의 saveUser를 실행하고
ItemRepository 클래스의 saveItem을 실행한다
void ItemRepository::saveItem(UserRepository* userRepository)
{
// saveItem을 실행하는순간 Lock을 잠근다
lock_guard<std::mutex> lock_guard(_mutex);
// ItemRepository에서 Lock을 잠근후 FindByUserId를 실행한다.
User* user = userRepository->FindByUserId(100);
}
// saveUser를 실행하는순간 Lock를 잠근다
void UserRepository::saveUser(ItemRepository* itemRepository)
{
// saveItem을 실행하는순간 Lock을 잠근다
lock_guard<std::mutex> lock_guard(_mutex);
// UserRepository에서 Lock을 잠근후 FindByItemId를 실행한다.
Item* item = itemRepository->FindByItemId(100);
}
User* FindByUserId(int userId)
{
lock_guard<std::mutex> lock_guard(_mutex);
return nullptr;
}
Item* FindByItemId(int itemId)
{
lock_guard<std::mutex> lock_guard(_mutex);
return nullptr;
}
지금 현재 위와 같은 상황이 발생했다.
ItemRepository와
UserRepository는 멀티쓰레드에서 실행되기 때문에 누구 먼저 실행된다는 보장이 없다.
병렬적으로 실행되기에 동시에 내가 가진 자원에 Lock을 잠그고 서로 다른 자원에 접근한다면 교착상태에 빠지게 된다
--- 상황
1) t1 스레드가 User Lock을 잠금
1) t2 스레드가 Item Lock을 잠금
2) t1 스레드가 Item 에 접근 하지만 t2가 Lock을 잠궜음
2) t2 스레드가 User 에 접근 하지만 t1이 Lock을 잠궜음
서로 이렇게 교착상태에 빠짐
void ItemRepository::saveItem(UserRepository* userRepository)
{
// ItemRepository에서 FindByUserId를 실행한다 (하지만 saveUser에서 Lock을 잡았기때문에 대기).
User* user = userRepository->FindByUserId(100);
// saveItem을 실행하는순간 Lock을 잠근다
lock_guard<std::mutex> lock_guard(_mutex);
}
void UserRepository::saveUser(ItemRepository* itemRepository)
{
// saveUser를 실행하는순간 UserRepository Lock를 잠근다
lock_guard<std::mutex> lock_guard(_mutex);
// UserRepository에서 Lock을 잠근후 FindByItemId를 실행한다.
// ItemLock잠김
Item* item = itemRepository->FindByItemId(100);
// Item Lock 해제
// User Lock 해제
}
User* FindByUserId(int userId)
{
lock_guard<std::mutex> lock_guard(_mutex);
return nullptr;
}
Item* FindByItemId(int itemId)
{
lock_guard<std::mutex> lock_guard(_mutex);
return nullptr;
}
이걸 해결해줄수 있는 방법은 간단한데, 서로의 순환구조를 풀어주는것이다.
-- 해결책
1) t1 스레드가 User에 접근하지만 Item이 Lock을 잠금 t2가 끝날때까지 대기함
2) t2 순차적으로 일을 처리한후 LOCK을 해제
3) t1 스레드가 깨어남
4) t1 스레드가 일을 처리함
느낀점:
아직도 어렵다;
'개발공부 > GAME 개발' 카테고리의 다른 글
멀티스레드 프로그래밍에 관해서 공부해보자 1 (0) | 2022.07.09 |
---|
Comments