2020년 7월 1일 수요일

C++ 첨으로 Theadlock

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

class Thread

{

public:

Thread(Thread* parent) : parent(parent), bStop(false)

{

ableThreadNum = std::thread::hardware_concurrency() - 1;

Init();

}

~Thread()

{

bStop = true;

conditionVar.notify_all();

for (auto& thread : threads) thread.join();

}

void AddTask(std::function<void()>&& task);

const int& GetAbleThreadNum() { return ableThreadNum; }

private:

void Init();

void Invoke();

private:

Thread* parent;

std::vector<std::thread> threads;

std::queue<std::function<void()>> tasks;

std::condition_variable conditionVar;

std::mutex taskMutex;

int ableThreadNum;

bool bStop;

};

void Thread::Init()

{

for (int i = 0; i < ableThreadNum; i++)

threads.emplace_back(std::thread(&Thread::Invoke, this));

}

void Thread::Invoke()

{

std::function<void()> task;

while (true)

{

std::unique_lock<std::mutex> lock(taskMutex);

{

conditionVar.wait(lock, [this]() {return !tasks.empty() || bStop; });

if (tasks.empty() && bStop)

{

std::cout << "A thread exit" << std::endl;

return;

}

task = tasks.front();

tasks.pop();

}

lock.unlock();

if(task) (task)();

}

}

void Thread::AddTask(std::function<void()>&& process)

{

if (threads.empty())

process();

std::unique_lock<std::mutex> lock(taskMutex);

{

tasks.push(process);

}

lock.unlock();

conditionVar.notify_one();

}

위는 내가 사용한 thread 클래스.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

void main()

{

Thread* thread = new Thread(nullptr);;

std::function<void()> func1 = []() { std::cout << "JobDone" << std::endl; };

std::cout << " total additonal thread is " << thread->GetAbleThreadNum() << std::endl;

for (int i = 0; i < 3; i++)

{

thread->AddTask([i, thread, &func1]()

{

int nJob = 0;

for (int j = 0; j < 3; j++)

{

thread->AddTask([thread, &func1, &nJob]()

{

thread->AddTask(std::forward<std::function<void()>>(func1));

nJob++;

});

}

while (nJob < 3)

{

std::cout << "stucking in " + std::to_string(i) + " while loop " << std::endl;

}

});

}

thread->~Thread();

std::cout << " parent finding end "<< std::endl;

}

아래는 그걸로 만든 데드록 예시.

왜 이런일이 발생하느냐.

운영체제에서 mutex 가지고 놀 때 알려주는 deadlock 의 조건을 생각하면 된다.

난 quad core 컴퓨터라서 main thead 외에 3개의 추가 스레드가 주어진다.

main thread 는 main 문을 돌고 있을 것이다.

스레드는 3개 뿐인데 job 의 갯수는 9개 이다. 게다가 3, 3, 3 으로 나누어져 있어서 나뉜 내부의 각각은 종속적이다. 왜냐하면 while(job < 3) 이 있기 때문이다. 여기서 job 의 갯수가 3인 것과 스레드 갯수를 생각해보면 답이 나온다. 그 결과는 스레드 각각 while 문에 잡혀있는 위의 스크린 샷이다.

가만히 그것만 골똘히 생각하면 쉽게 답이 유추되지만 이걸 의식하지 않으면 거기까지 생각이 미치지 않는다.

다 그렇단말이 아니라 내가 그렇다.

몇시간 뻘짓했다.

댓글 없음:

댓글 쓰기

List