Mutex์์ ๋น๊ต
์ฝ๋
#include <iostream>
#include <thread>
#include <vector>
#include <atomic>
#include <random>
#include <mutex>
using namespace std;
class Node {
public:
int value;
Node* next;
Node() : value(0) { next = NULL; }
Node(int k_value) {
next = NULL;
value = k_value;
}
};
int node_n;
//random ๊ตฌํ
random_device rd;
mt19937 gen(rd());
uniform_int_distribution<> dis(0, 10);
//์ถ๋ ฅ์ ์ํ mutex
mutex mut;
class LFStack {
private:
Node * head;
public:
void printNodes() {
int size = 0;
while (head != nullptr) {
size++;
head = head->next;
}
cout << size << endl;
}
void push(Node* newNode) {
Node* oldHead;
mut.lock();
oldHead = head;
newNode->next = oldHead;
head = newNode;
mut.unlock();
}
Node* pop() {
Node* oldHead; Node* newHead;
mut.lock();
if ((oldHead = head) == nullptr) {
mut.unlock();
return nullptr;
}
newHead = oldHead->next;
head = newHead;
mut.unlock();
return oldHead;
}
};
LFStack* FreeList;
LFStack* HeadList;
void subThread() {
// random n, m
int n = dis(gen);
int m = dis(gen);
int num = 10000; // while๋ฌธ ๋ฐ๋ณต ํ์
while (num--) {
for (int i = 0; i < n; i++)
{
// free_list์ ์์ผ๋ฉด head_list์ ์ฎ๊ธฐ๋ ์์
Node* tmp = FreeList->pop();
if (tmp == nullptr)
continue;
HeadList->push(tmp);
}
for (int i = 0; i<m; i++) {
// head_list์ ์์ผ๋ฉด free_list์ ์ฎ๊ธฐ๋ ์์
Node* tmp = HeadList->pop();
if (tmp == nullptr)
continue;
FreeList->push(tmp);
}
}
}
int main() {
// free, head list ์์ฑ
FreeList = new LFStack();
HeadList = new LFStack();
// ๋
ธ๋ ์์ฑ ๋ฐ free_list์ ์ฝ์
node_n = 100000; // ๋
ธ๋ ๊ฐฏ์
for (int i = node_n - 1; i >= 0; i--) {
Node* node = new Node(i);
FreeList->push(node);
}
// ์ค๋ ๋ ์์ฑ ๋ฐ ๋์ ์์
vector<thread> threads;
int n = 5; // ์ค๋ ๋ ๊ฐฏ์
for (int i = 0; i < n; i++) {
threads.emplace_back(subThread);
}
for (auto &t : threads)
t.join();
threads.clear();
FreeList->printNodes();
HeadList->printNodes();
cin >> n;
}
๊ฒฐ๊ณผ
- ์คํ์กฐ๊ฑด
๋ ธ๋ ๊ฐฏ์ | thread | while๋ฌธ ์ํํ์ |
100,000 | 5 | 10,000 |
- ๊ฒฐ๊ณผ
๊ตฌ๋ถ | FreeList ๋ ธ๋ ์ | HeadList ๋ ธ๋ ์ |
1 | 40,000 | 60,000 |
2 | 100,000 | 0 |
3 | 96,091 | 3,909 |
lock ๊ธฐ๋ฒ์ผ๋ก ์ํธ๋ฐฐ์ ๋ฅผ ํด์ฃผ์๊ธฐ ๋๋ฌธ์, ๊ฒฐ๊ณผ๋ ์ ํํ๊ฒ ์ ๋์จ๋ค.
์ฑ๋ฅ ๋น๊ต
์คํ ์กฐ๊ฑด
๋ ธ๋ ๊ฐฏ์ | while๋ฌธ ์ํํ์ | (n,m) |
100,000๊ฐ | 10,000ํ | ๊ฐ ์ค๋ ๋์์ (10,10) |
๋น๊ตํ๊ธฐ ์ํด ์กฐ๊ฑด์ ๋ง์ถฐ์ฃผ์๋ค.
๊ตฌ๋ถ | thread ๊ฐฏ์ |
1 | 10 |
2 | 100 |
๊ฒฐ๊ณผ 1
๊ตฌ๋ถ | memory ์๋น | CPU ์ฌ์ฉ์๊ฐ(ms) |
Counter (lock-free) | 7.2MB | 2755 |
Mutex (lock) | 6.8MB | 9259 |
<Counter>
<Mutex>
๊ฒฐ๊ณผ 2
๊ตฌ๋ถ | memory ์๋น | CPU ์ฌ์ฉ์๊ฐ(ms) |
Counter (lock-free) | 7.1MB | 29661 |
Mutex (lock) | 12.5MB | 98597 |
<Counter>
<Mutex>
ํด์
Counter๋ฅผ ์ด์ฉํ lock-free ๊ธฐ๋ฒ๊ณผ Mutex๋ฅผ ์ด์ฉํ lock ๊ธฐ๋ฒ์ CPU ์ฌ์ฉ์๊ฐ์ 3๋ฐฐ ๊ฐ๊น์ด ์ฐจ์ด๊ฐ ๋ฌ๋ค. ์ด๋ lock ๊ธฐ๋ฒ ์ฌ์ฉ ์ Blocking ํ๋ก๊ทธ๋จ์ด ๋๋ฏ๋ก ์ค๋ ๋๋ค์ด lock ๋ณ๋ชฉํ์์ ์ผ์ผํค๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ํด์๋๋ค.
๋ํ Counter๋ฅผ ์ด์ฉํ ๊ธฐ๋ฒ์ ์ค๋ ๋์ ์๊ฐ ์ฆ๊ฐํด๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ด ๋น์ทํ๋๋ฐ, Mutex ๊ธฐ๋ฒ์ ์ค๋ ๋์ ์๊ฐ ์ฆ๊ฐํจ์ ๋ฐ๋ผ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋๋ ์ฆ๊ฐํ์๋ค. ์ด๋ long long ์ ์ํ์ ์ฌ์ฉํ๋ Counter ๊ธฐ๋ฒ์ ๊ฒฝ์ฐ ๋ธ๋ก์ด ๋๋๋ฉด ํด๋น ๋ณ์๊ฐ ์๋ฉธ๋์ง๋ง, Node* ๊ฐ์ฒด ํฌ์ธํฐํ์ ์ฌ์ฉํ๋ Mutex ๊ธฐ๋ฒ์ ๊ฒฝ์ฐ GC๊ฐ ์๋ c++์์ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๊ทธ๋๋ก ๋จ์์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก lock-free ๊ธฐ๋ฒ์ ABA ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๊ณ , ๊ตฌํ ์ Overhead๋ฅผ ์ค์ผ ์ ์๋ค๋ฉด thread๊ฐ ๋ณ๋ ฌ๋ก ๋ง์ด ๋์ํ๋ ์ํฉ์์ lock์ ๋ณ๋ชฉ์ด ์ผ์ด๋๋ lock ์ํธ๋ฐฐ์ ๊ธฐ๋ฒ์ ๋์ฒดํ๊ธฐ ์ํ ์ข์ ๋ฐฉ์์ด ๋ ์์๋ค.
์ฐธ๊ณ ์ฌ์ดํธ
https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
http://www.cplusplus.com/reference/atomic/atomic/compare_exchange_weak/
https://felixblog.tistory.com/23
https://www.sysnet.pe.kr/2/0/1458
https://decdream.tistory.com/342
https://mountrivers.github.io/p014garbage/
https://m.blog.naver.com/jjoommnn/130129196122
https://en.wikipedia.org/wiki/ABA_problem
https://blog.naver.com/jjoommnn/130040068875?proxyReferer=https%3A%2F%2Fwww.google.com%2F
https://dojang.io/mod/page/view.php?id=472
=> ๋
Comment