- SET
: ์์ดํ ์ ์ค๋ณต์ ํ์ฉํ์ง ์์
: ์ ๋ ฌ๋์ด ์ ์ฅ๋จ (unordered_set์ด ์๋) - ๊ฒ์ ํจ์จ ์ฆ๊ฐ
: ์ฝ์ ์ญ์ ์ ํจ์จ์ฑ์ ์ํด ๋งํฌ๋๋ฆฌ์คํธ ๊ตฌํ
: ๊ตฌํ ) add, remove, contains
: ํ๋ ) ๋ฆฌ์คํธ์ ์ ์ฅ๋๋ ๊ฐ
: ๋ฉ์๋
- add(x) : ์งํฉ์ x์ถ๊ฐ, ์ฑ๊ณต ์ true
- remove(x) : ์งํฉ์์ x ์ ๊ฑฐ, ์ฑ๊ณต ์ true
- contains(x) : ์งํฉ์ x๊ฐ ์๋ค๋ฉด true
: ์ถ๊ฐ ๊ตฌํ ) ๋ณด์ด ๋ ธ๋ - ๊ฒ์ ํจ์จ์ ์ํด ํญ์ ์กด์ฌํ๋ Head(MAXINT)์ Tail๋ ธ๋(-MAXINT)๋ฅผ ๊ฐ๋๋ก ํจ
- ์ฑ๊ธด ๋๊ธฐํ
: ๋ฆฌ์คํธ๋ ํ๋์ ์ ๊ธ์ ๊ฐ์ง
: ๋ชจ๋ ๋งค์๋ ํธ์ถ์ ์ด ์ ๊ธ์ ํตํด Critical Section์ผ๋ก ์งํ๋จ ( = ๋ชจ๋ ๋งค์๋๋ ์ ๊ธ์ ๊ฐ๋ ๋์์๋ง ๋ฆฌ์คํธ์ ์ ๊ทผ)
: ๋ฌธ์ ) ๊ฒฝ์์ด ๋ฎ์ ๊ฒฝ์ฐ ์ ํํ๋ฉด ์ข์. ๊ฒฝ์์ด ๋์ ๊ฒฝ์ฐ ์ฑ๋ฅ ์ ํ / Blocking
constexpr int MAX_THREADS = 16; // ์ต๋ ์ฐ๋ ๋ ์๋ฅผ ์์๋ก ์ ์
class NODE {
std::mutex nl; // ๊ฐ ๋
ธ๋์ ๋ํ ๋ฎคํ
์ค
public:
int v; // ๋
ธ๋์ ๊ฐ
NODE* next; // ๋ค์ ๋
ธ๋์ ํฌ์ธํฐ
bool removed; // ์ญ์ ์ฌ๋ถ๋ฅผ ๋ํ๋ด๋ ํ๋๊ทธ
NODE() : v(-1), next(nullptr), removed(false) {}
NODE(int x) : v(x), next(nullptr), removed(false) {}
void Lock() // ๋
ธ๋ ๋ฝ ํจ์
{
nl.lock();
}
void Unlock() // ๋
ธ๋ ์ธ๋ฝ ํจ์
{
nl.unlock();
}
};
class SET {
NODE head, tail; // ํค๋์ ํ
์ผ ๋
ธ๋
mutex ll; // ์ ์ญ ๋ฎคํ
์ค
public:
SET()
{
head.v = 0x80000000; // ํค๋์ ๊ฐ ์ด๊ธฐํ
tail.v = 0x7FFFFFFF; // ํ
์ผ์ ๊ฐ ์ด๊ธฐํ
head.next = &tail; // ํค๋์ ๋ค์ ๋
ธ๋๋ฅผ ํ
์ผ๋ก ์ค์
}
bool ADD(int x) // ์ฝ์
์ฐ์ฐ
{
NODE* prev = &head;
ll.lock(); // ์ ์ญ ๋ฝ ํ๋
NODE* curr = prev->next;
while (curr->v < x) { // ์ ๋ ฌ๋ ์์น ์ฐพ๊ธฐ
prev = curr;
curr = curr->next;
}
if (curr->v != x) { // ์ค๋ณต๋ ๊ฐ์ด ์์ ๋
NODE* node = new NODE{ x }; // ์๋ก์ด ๋
ธ๋ ์์ฑ
node->next = curr; // ์๋ก์ด ๋
ธ๋๋ฅผ ์ฐ๊ฒฐ
prev->next = node; // ์ด์ ๋
ธ๋์ ์๋ก์ด ๋
ธ๋ ์ฐ๊ฒฐ
ll.unlock(); // ์ ์ญ ๋ฝ ํด์
return true;
}
else // ์ด๋ฏธ ์กด์ฌํ๋ ๊ฐ์ผ ๋
{
ll.unlock(); // ์ ์ญ ๋ฝ ํด์
return false;
}
}
bool REMOVE(int x) // ์ญ์ ์ฐ์ฐ
{
NODE* prev = &head;
ll.lock(); // ์ ์ญ ๋ฝ ํ๋
NODE* curr = prev->next;
while (curr->v < x) { // ์ญ์ ํ ๊ฐ ์์น ์ฐพ๊ธฐ
prev = curr;
curr = curr->next;
}
if (curr->v != x) { // ์ญ์ ํ ๊ฐ์ด ์กด์ฌํ์ง ์์ ๋
ll.unlock(); // ์ ์ญ ๋ฝ ํด์
return false;
}
else { // ์ญ์ ํ ๊ฐ์ด ์กด์ฌํ ๋
prev->next = curr->next; // ์ด์ ๋
ธ๋์ ๋ค์ ๋
ธ๋๋ฅผ ์ฐ๊ฒฐ
delete curr; // ๋
ธ๋ ์ญ์
ll.unlock(); // ์ ์ญ ๋ฝ ํด์
return true;
}
}
bool CONTAINS(int x) // ๊ฒ์ ์ฐ์ฐ
{
NODE* prev = &head;
ll.lock(); // ์ ์ญ ๋ฝ ํ๋
NODE* curr = prev->next;
while (curr->v < x) { // ๊ฒ์ํ ๊ฐ ์์น ์ฐพ๊ธฐ
prev = curr;
curr = curr->next;
}
bool res = (curr->v == x); // ๊ฐ ์กด์ฌ ์ฌ๋ถ ํ์ธ
ll.unlock(); // ์ ์ญ ๋ฝ ํด์
return res;
}
void print20() // ์ฒ์ 20๊ฐ์ ๋
ธ๋ ๊ฐ ์ถ๋ ฅ
{
NODE* p = head.next;
for (int i = 0; i < 20; ++i) {
if (p == &tail) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear() // ์ ์ฒด ๋
ธ๋ ์ญ์
{
NODE* p = head.next;
while (p != &tail) {
NODE* t = p;
p = p->next;
delete t;
}
head.next = &tail;
}
};
: ๊ตฌํ
- pred์ curr๋ฅผ ์ฌ์ฉํ add&remove
- ์ธ๋ฐํ ๋๊ธฐํ
: ์ ์ฒด ๋ฆฌ์คํธ๋ฅผ ํ ๋ฒ์ ์ ๊ทธ๋ ๊ฒ๋ณด๋ค ๊ฐ๋ณ ๋ ธ๋๋ฅผ ์ ๊ทธ๋ ๊ฒ์ด ๋ณํ์ฑ ํฅ์
: ๊ฐ๊ฐ์ ๋ ธ๋์ ์ ๊ธ์ ๋
: Node์ next field๋ฅผ ๋ณ๊ฒฝ ์ ๋ฐ๋์ Lock()์ ์ป์ ํ ๋ณ๊ฒฝ
: ์ฃผ์์
- Add, Remove ์์ ์ Pred, Curr๊ฐ ๊ฐ๋ฆฌํค๋ ๋ ธ๋๋ Locking ๋์ด์ผ ํจ
- Head๋ถํฐ Node ์ด๋ ์ Lock์ ์ ๊ทธ๋ฉด์ ์ด๋ ํ์
class F_SET {
NODE head, tail;
public:
F_SET()
{
head.v = 0x80000000;
tail.v = 0x7FFFFFFF;
head.next = &tail;
}
bool ADD(int x)
{
NODE* prev = &head;
prev->Lock(); // 1. ํค๋ ๋ฝ ์ ๊ธ
NODE* curr = prev->next;
curr->Lock(); // 2. ํค๋์ ๋ค์ ๋
ธ๋์ ๋ฝ ์ ๊ธ
while (curr->v < x) {
prev->Unlock(); // 3. ์ด์ ๋
ธ๋ ๋ฝ ํด์
prev = curr;
curr = curr->next; // 4. ์๋ก์ด ํ์ฌ ๋
ธ๋ ๋ฝ ์ ๊ธ
curr->Lock();
}
if (curr->v != x) {
NODE* node = new NODE{ x };
node->next = curr;
prev->next = node;
prev->Unlock(); curr->Unlock(); // 5. ์ด์ ๊ณผ ํ์ฌ ๋
ธ๋ ๋ฝ ํด์
return true;
}
else
{
prev->Unlock(); curr->Unlock();
return false;
}
}
bool REMOVE(int x)
{
NODE* prev = &head;
prev->Lock();
NODE* curr = prev->next;
curr->Lock();
while (curr->v < x) {
prev->Unlock();
prev = curr;
curr = curr->next;
curr->Lock();
}
if (curr->v != x) {
prev->Unlock(); curr->Unlock();
return false;
}
else {
prev->next = curr->next;
prev->Unlock(); curr->Unlock();
delete curr;
return true;
}
}
bool CONTAINS(int x)
{
NODE* prev = &head;
prev->Lock();
NODE* curr = prev->next;
curr->Lock();
while (curr->v < x) {
prev->Unlock();
prev = curr;
curr = curr->next;
curr->Lock();
}
bool res = (curr->v == x);
prev->Unlock(); curr->Unlock();
return res;
}
void print20()
{
NODE* p = head.next;
for (int i = 0; i < 20; ++i) {
if (p == &tail) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear()
{
NODE* p = head.next;
while (p != &tail) {
NODE* t = p;
p = p->next;
delete t;
}
head.next = &tail;
}
};
: ์ฑ๋ฅ ์ ํ ์์ธ
- ์ ๊ธ์ ํ๋๊ณผ ํด์ ๊ฐ ๋น๋ฒ, ๋ฆฌ์คํธ๊ฐ ๊ธธ์ด์ง๋ ๊ฒฝ์ฐ ์ฑ๋ฅ์ด ๋งค์ฐ ๋จ์ด์ง
→ ์ด๋ ์ ์ ๊ธ์ ํ์ง ์๋๋ค? : DataRace
- Crash ( or ๋ฌดํ๋ฃจํ ) : ์ ๊ฑฐ๋ Node๋ผ๋ next๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด tail์ด ๋์ค๊ฒ ํจ (vaildation)
- ์ค๋์ : pred์ curr๋ฅผ ์ ๊ทผ ํ ์ ๋๋ก ์ ๊ฐ๋์ง ๊ฒ์ฌํ๊ณ ์๋ชป ์ ๊ถ์ผ๋ฉด ์ฒ์๋ถํฐ ๋ค์ ์คํ
- ๋์ฒ์ ๋๊ธฐํ
: ์ ๊ฑฐ๋ ๋ ธ๋๋ฅผ 'delete' ํ์ง ์์ (next ํ๋์ ์ค์ผ ๋ฐฉ์ง)
: Memory Leak ๋ฐ์
: vaildation ์กฐ๊ฑด ๊ฒ์ฌ
- pred, curr๊ฐ ๋ฆฌ์คํธ์ ์กด์ฌํ๋ค / pred์ curr ์ฌ์ด์ ๋ค๋ฅธ ๋ ธ๋๊ฐ ์์
: ๊ธฐ์ ๋ฐ์ ํ๋ฅ ์กด์ฌ (๋ค๋ฅธ ์ฐ๋ ๋๊ฐ pred์ curr๋ฅผ ๊ณ์ ์์ ํ๋ ๊ฒฝ์ฐ ๊ณ์ ์ฌ์๋๋ฅผ ํ๋ฉด์ ์ง์ฐ)
class O_SET {
NODE head, tail;
public:
O_SET()
{
head.v = 0x80000000;
tail.v = 0x7FFFFFFF;
head.next = &tail;
}
bool validate(const NODE* prev, const NODE* curr) // ํ์ฌ ๋
ธ๋์ ์ด์ ๋
ธ๋๊ฐ ์ ํจํ ์์๋ฅผ ๊ฐ์ง๋์ง ํ์ธ
{
NODE* ptr = &head;
while (ptr->v <= prev->v) {
if (ptr == prev)
return ptr->next == curr;
ptr = ptr->next;
}
return false;
}
bool ADD(int x)
{
while (true) {
NODE* prev = &head;
NODE* curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock(); // ์ด์ ๋
ธ๋์ ํ์ฌ ๋
ธ๋์ ๋ฝ์ ์ ๊ธ
if (true == validate(prev, curr)) { // ๋
ธ๋์ ์ ํจ์ฑ์ ๊ฒ์ฆํ๊ณ ์ ํจํ ๊ฒฝ์ฐ
if (curr->v != x) {
NODE* node = new NODE{ x };
node->next = curr;
prev->next = node;
prev->Unlock(); curr->Unlock(); // ๋ฝ ํด์
return true;
}
else
{
prev->Unlock(); curr->Unlock(); // ๋ฝ ํด์
return false;
}
}
else {
prev->Unlock(); curr->Unlock(); // ๋ฝ ํด์
}
}
}
bool REMOVE(int x)
{
while (true) {
NODE* prev = &head;
NODE* curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) { // ๋
ธ๋๊ฐ ์ ํจํ ๊ฒฝ์ฐ ์ญ์
if (curr->v != x) {
prev->Unlock(); curr->Unlock();
return false;
}
else {
prev->next = curr->next;
prev->Unlock(); curr->Unlock();
// delete curr;
return true;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool CONTAINS(int x)
{
while (true) {
NODE* prev = &head;
NODE* curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
bool res = (curr->v == x);
prev->Unlock(); curr->Unlock();
return res;
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
void print20()
{
NODE* p = head.next;
for (int i = 0; i < 20; ++i) {
if (p == &tail) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear()
{
NODE* p = head.next;
while (p != &tail) {
NODE* t = p;
p = p->next;
delete t;
}
head.next = &tail;
}
};
: Lock์ ํ์๋ ๋น์ฝ์ ์ผ๋ก ๊ฐ์ํ๋, ๋ฆฌ์คํธ๋ฅผ ๋ ๋ฒ ์ํํด์ผ ํจ(์ค๋ฒํค๋)
→ ๋ค์ ์ํํ์ง ์๋ ์๊ณ ๋ฆฌ์ฆ ์์ฑ ํ์
- ๊ฒ์ผ๋ฅธ ๋๊ธฐํ
: Contains() ๋ฉ์๋๋ ์์ฃผ ํธ์ถ๋๋ ๋ฉ์๋์ธ๋ฐ.. Wait-Free๋ฉด ์ข๊ฒ ..
: ๊ฐ ๋ ธ๋์ marked ํ๋๋ฅผ ์ถ๊ฐํด ๊ทธ ๋ ธ๋๊ฐ ์งํฉ์์ ์ ๊ฑฐ๋์๋์ง ํ์
- marked == true : ์ ๊ฑฐ๋จ
- marking ์ค์ ์ ๊ฑฐ ๋ณด๋ค ๋ฐ๋์ ๋จผ์ ์ํ ( + ์ ๊ธ์ ํ๋ํ ํ ์ํ)
- marking ๋์ด ์์ง ์์ ๋ชจ๋ Node๋ ์ค์ ๋ฆฌ์คํธ์ ์กด์ฌํ๋(์ด์์๋) Node!!!
class Z_SET {
NODE head, tail;
public:
Z_SET()
{
head.v = 0x80000000;
tail.v = 0x7FFFFFFF;
head.next = &tail;
}
bool validate(const NODE* prev, const NODE* curr)
{
return (false == prev->removed) // ์ด์ ๋
ธ๋๊ฐ ์ ๊ฑฐ๋์ง ์์๋์ง ํ์ธ
&& (false == curr->removed) // ํ์ฌ ๋
ธ๋๊ฐ ์ ๊ฑฐ๋์ง ์์๋์ง ํ์ธ
&& (prev->next == curr); // ์ด์ ๋
ธ๋์ ๋ค์ ๋
ธ๋๊ฐ ํ์ฌ ๋
ธ๋์ธ์ง ํ์ธ
}
bool ADD(int x)
{
while (true) {
NODE* prev = &head;
NODE* curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
NODE* node = new NODE{ x };
node->next = curr;
prev->next = node;
prev->Unlock(); curr->Unlock();
return true;
}
else
{
prev->Unlock(); curr->Unlock();
return false;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool REMOVE(int x)
{
while (true) {
NODE* prev = &head;
NODE* curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
prev->Unlock(); curr->Unlock();
return false;
}
else {
curr->removed = true;
prev->next = curr->next;
prev->Unlock(); curr->Unlock();
// delete curr;
return true;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool CONTAINS(int x)
{
NODE* curr = head.next;
while (curr->v < x) {
curr = curr->next;
}
return (curr->v == x) && (false == curr->removed);
}
void print20()
{
NODE* p = head.next;
for (int i = 0; i < 20; ++i) {
if (p == &tail) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear()
{
NODE* p = head.next;
while (p != &tail) {
NODE* t = p;
p = p->next;
delete t;
}
head.next = &tail;
}
};
: ์ผ๋จ Blocking์ด๋ค
: Convoying - ํ ์ฐ๋ ๋๊ฐ Lock์ ์ป์ ์ฑ๋ก ์ง์ฐ๋๋ฉด, ๋ค๋ฅธ ์ฐ๋ ๋ ์ญ์ ์ง์ฐ๋๊ฒ ๋จ
- ๋ฉ๋ชจ๋ฆฌ ๋ฆญ(๋ฉ๋ชจ๋ฆฌ ๋์) ํด๊ฒฐ
: Free List
- Delete ํ์ง ์๊ณ ๋ชจ์ ๋์ → marking์ด ํด์ ๋๋ ์๊ฐ ์ค์๋ ๊ฐ๋ฅ
- ์ธ์ ๊ฐ๋ ์ฌ์ฌ์ฉ → ์๋ฌด๋ remove๋ node๋ฅผ ๊ฐ๋ฆฌํค์ง ์์ ๋
: shared_ptr
- ์๋ฌด๋ ๊ฐ๋ฆฌํค์ง ์๋ ๋ ธ๋ ์ ๊ฑฐ์ ์ ํฉ
- ๊ฐ์ฒด์ reference counter๋ฅผ ๋๊ณ ์ด๋ฅผ ํตํด ์์ผ๋ก ์ฐ์ด์ง ์์ ๊ฐ์ฒด๋ฅผ ํ๋ณํด์ ์๋ ์ญ์ ํ๋ ์๋ฆฌ
- Node์ next๋ฅผ ์ด๊ฒ์ผ๋ก ๊ตฌํ
class SP_NODE {
std::mutex nl;
public:
int v;
shared_ptr<SP_NODE> next;
bool removed;
SP_NODE() : v(-1), next(nullptr), removed(false) {}
SP_NODE(int x) : v(x), next(nullptr), removed(false) {}
void Lock()
{
nl.lock();
}
void Unlock()
{
nl.unlock();
}
};
class ZSP_SET {
std::shared_ptr <SP_NODE> head, tail;
public:
ZSP_SET()
{
head = make_shared<SP_NODE>(0x80000000);
tail = make_shared<SP_NODE>(0x7FFFFFFF);
head->next = tail;
}
bool validate(const shared_ptr<SP_NODE>& prev,
const shared_ptr<SP_NODE>& curr)
{
return (false == prev->removed)
&& (false == curr->removed)
&& (prev->next == curr);
}
bool ADD(int x)
{
while (true) {
shared_ptr<SP_NODE> prev = head;
shared_ptr<SP_NODE> curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
shared_ptr<SP_NODE> node = make_shared<SP_NODE>(x);
node->next = curr;
prev->next = node;
prev->Unlock(); curr->Unlock();
return true;
}
else
{
prev->Unlock(); curr->Unlock();
return false;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool REMOVE(int x)
{
while (true) {
shared_ptr<SP_NODE> prev = head;
shared_ptr<SP_NODE> curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
prev->Unlock(); curr->Unlock();
return false;
}
else {
curr->removed = true;
prev->next = curr->next;
prev->Unlock(); curr->Unlock();
return true;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool CONTAINS(int x)
{
shared_ptr<SP_NODE> curr = head->next;
while (curr->v < x) {
curr = curr->next;
}
return (curr->v == x) && (false == curr->removed);
}
void print20()
{
shared_ptr<SP_NODE> p = head->next;
for (int i = 0; i < 20; ++i) {
if (p == tail) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear()
{
head->next = tail;
}
};
: ๋์๊ฐ๋๊ฐ? No!
- shared_ptr ๊ฐ์ฒด๋ฅผ load, store ํ๋ ๊ฒ์ atomic์ด ์๋ (auto curr = prev->next ์ด๊ฑฐ DATA RACE)
→ ๊ณต์ ํ๋ shared_ptr ๊ฐ์ฒด๋ฅผ atomicํ๊ฒ ์ํํ๋ค (atomic_load, atomic_exchange)
class ZSP_SET2 {
std::shared_ptr <SP_NODE> head, tail;
public:
ZSP_SET2()
{
head = make_shared<SP_NODE>(0x80000000);
tail = make_shared<SP_NODE>(0x7FFFFFFF);
head->next = tail;
}
bool validate(const shared_ptr<SP_NODE>& prev,
const shared_ptr<SP_NODE>& curr)
{
return (false == prev->removed)
&& (false == curr->removed)
&& (prev->next == curr);
}
bool ADD(int x)
{
while (true) {
shared_ptr<SP_NODE> prev = head;
shared_ptr<SP_NODE> curr = atomic_load(&prev->next);
while (curr->v < x) {
prev = curr;
curr = atomic_load(&curr->next);
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
shared_ptr<SP_NODE> node = make_shared<SP_NODE>(x);
node->next = curr;
atomic_exchange(&prev->next, node);
prev->Unlock(); curr->Unlock();
return true;
}
else
{
prev->Unlock(); curr->Unlock();
return false;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool REMOVE(int x)
{
while (true) {
shared_ptr<SP_NODE> prev = head;
shared_ptr<SP_NODE> curr = atomic_load(&prev->next);
while (curr->v < x) {
prev = curr;
curr = atomic_load(&curr->next);
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
prev->Unlock(); curr->Unlock();
return false;
}
else {
curr->removed = true;
atomic_exchange(&prev->next, atomic_load(&curr->next));
prev->Unlock(); curr->Unlock();
return true;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool CONTAINS(int x)
{
shared_ptr<SP_NODE> curr = atomic_load(&head->next);
while (curr->v < x) {
curr = atomic_load(&curr->next);
}
return (curr->v == x) && (false == curr->removed);
}
void print20()
{
shared_ptr<SP_NODE> p = head->next;
for (int i = 0; i < 20; ++i) {
if (p == tail) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear()
{
head->next = tail;
}
};
: ์ฑ๋ฅ ๋ฌธ์ ๋ฐ์
- atomic_load์ atomic_exchange๋ ํ๋์ lock์ผ๋ก ๊ตฌํ๋์ด ์๋ค
→ shared_ptr ๊ฐ๊ฐ์ด ๋ณ๋์ lock์ ๊ฐ๋๋ก atomic_shared_ptr๋ฅผ ์ ์ํด์ ์ฌ์ฉ
class ASP_NODE {
std::mutex nl;
public:
int v;
atomic<shared_ptr<ASP_NODE>> next;
bool removed;
ASP_NODE() : v(-1), next(nullptr), removed(false) {}
ASP_NODE(int x) : v(x), next(nullptr), removed(false) {}
void Lock()
{
nl.lock();
}
void Unlock()
{
nl.unlock();
}
};
class ZSP_SET3 {
std::atomic<std::shared_ptr <ASP_NODE>> head, tail;
public:
ZSP_SET3()
{
head = make_shared<ASP_NODE>(0x80000000);
tail = make_shared<ASP_NODE>(0x7FFFFFFF);
head.load()->next = tail.load();
}
bool validate(const shared_ptr<ASP_NODE>& prev,
const shared_ptr<ASP_NODE>& curr)
{
return (false == prev->removed)
&& (false == curr->removed)
&& (prev->next.load() == curr);
}
bool ADD(int x)
{
while (true) {
shared_ptr<ASP_NODE> prev = head;
shared_ptr<ASP_NODE> curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
shared_ptr<ASP_NODE> node = make_shared<ASP_NODE>(x);
node->next = curr;
prev->next = node;
prev->Unlock(); curr->Unlock();
return true;
}
else
{
prev->Unlock(); curr->Unlock();
return false;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool REMOVE(int x)
{
while (true) {
shared_ptr<ASP_NODE> prev = head;
shared_ptr<ASP_NODE> curr = prev->next;
while (curr->v < x) {
prev = curr;
curr = curr->next;
}
prev->Lock(); curr->Lock();
if (true == validate(prev, curr)) {
if (curr->v != x) {
prev->Unlock(); curr->Unlock();
return false;
}
else {
curr->removed = true;
prev->next.store(curr->next);
prev->Unlock(); curr->Unlock();
return true;
}
}
else {
prev->Unlock(); curr->Unlock();
}
}
}
bool CONTAINS(int x)
{
shared_ptr<ASP_NODE> curr = head.load()->next;
while (curr->v < x) {
curr = curr->next;
}
return (curr->v == x) && (false == curr->removed);
}
void print20()
{
shared_ptr<ASP_NODE> p = head.load()->next;
for (int i = 0; i < 20; ++i) {
if (p == tail.load()) break;
cout << p->v << ", ";
p = p->next;
}
cout << endl;
}
void clear()
{
head.load()->next = tail.load();
}
};
: C++20๋ถํฐ๋ atomic<shared_ptr<T>> ๋ฅผ ์ง์ํจ - ๊ทผ๋ฐ blocking ๊ตฌํ์ด๋ค ใ
: atomicํ shared_ptr์ ๋๋ฆฌ๋ค → mutex, blocking!
→ ํจ์จ์ ์ธ(non-blocking) atomic_shared_ptr์ด ํ์ํ๋ค
- Look-free ์๊ณ ๋ฆฌ์ฆ
: ์ฌ๋ฌ ๊ฐ์ ์ฐ๋ ๋์์ ๋์์ ํธ์ถ ์ ์ ํด์ง ๋จ์ ์๊ฐ๋ง๋ค ์ ์ด๋ ํ ๊ฐ์ ํธ์ถ์ด ์๋ฃ๋๋ ์๊ณ ๋ฆฌ์ฆ
: ๋ฉํฐ์ฐ๋ ๋์์ ๋์์ ํธ์ถํด๋ ์ ํํ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด ์ฃผ๋ ์๊ณ ๋ฆฌ์ฆ (STL X, Atomicํ ๋์)
: ์ฌ์ฉํ์ง ์์ผ๋ฉด ๋ค์ ๋ฌธ์ ๋ฐ์
- ๋ณ๋ ฌ์ฑ ๊ฐ์
- Priority Inversion (์ฐ์ ์์ ์ญ์ )
- Convoying
- ์ฑ๋ฅ ์ ํ & ๋
+ wait-free ์๊ณ ๋ฆฌ์ฆ : ํธ์ถ์ด ๋ค๋ฅธ ์ฐ๋ ๋์ ์ถฉ๋ํด๋ ๋ชจ๋ ๋๋ ์ด ์์ด ์๋ฃ๋จ
: Non-blocking ์๊ณ ๋ฆฌ์ฆ - ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ ์ด๋ค ์ํ์ ์๊ฑด ์๊ด์์ด ํธ์ถ ์๋ฃ
: CAS๊ฐ ์์ด๋ ๋๋ถ๋ถ์ non-blocking ์๊ณ ๋ฆฌ์ฆ๋ค์ ๊ตฌํํ ์ ์์
: CAS(&A, old, new);
: A์ ๊ฐ์ด old๋ฉด new๋ก ๋ฐ๊พธ๊ณ true๋ฅผ ๋ฆฌํด
: A๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ ๋จผ์ ์ ๋ฐ์ดํธ ํด์ false๊ฐ ๋์๋ค. ๋ชจ๋ ๊ฒ์ ํฌ๊ธฐํ๋ผ.
: ์๊ณ ๋ฆฌ์ฆ์ด ๋ฌด์ฒ ๋ณต์ก → ์ฆ๋ช ๋ ์๊ณ ๋ฆฌ์ฆ๋ง ์ฌ์ฉํ์
- Non-blocking ๊ตฌํ (๋น๋ฉ์ถค ๋๊ธฐํ)
: ๊ฒ์ผ๋ฅธ ๋๊ธฐํ์์ ์ถ๋ฐ
: Lock ์ฌ์ฉ ๊ธ์ง + ์๋ก ์ถฉ๋ํ๋ thread๋ CAS๋ก ์น๋ถ
: ADD ๊ตฌํ
- ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ *pred๋ฅผ remove ? → pred์ marking์ ํ์ธํ๋ฉด์ ๋ณ๊ฒฝ
- ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ *curr๋ฅผ remove? → Pred์ mark๊ฐ false์ธ ๊ฒ์ ํ์ธํ๋ฉด์ ๋ณ๊ฒฝ
- ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ *pred, *curr ์ฌ์ด์ ์๋ก์ด ๋ ธ๋๋ฅผ ๋ผ์ ๋ฃ์ผ๋ฉด? → pred์ next๊ฐ curr์ธ ๊ฒ์ ํ์ธํ๋ฉด์ ๋ณ๊ฒฝ
- pred์ curr๋ฅผ lockingํ์ง ์๊ธฐ์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๊ฒ์ถํ๋ ค๋ฉด next์ marking์ ๋์์ ๊ฐ์ํ๋ฉฐ CAS ์ํ
→ ๋์ CAS ๊ตฌํ ํ๊ณ : ํ ๋ฒ์ ํ๋์ ๋ณ์ ๋ฐ์ ๋ฐ๊พธ์ง ๋ชปํจ
→ ํ ์ฅ์์ ์ฃผ์์ Marking์ ๋์์ ์ ์ฅํ์. (ํน์ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ ๊ฐ๋ฅ)
: Remove ๊ตฌํ
- curr๋ฅผ delete? → curr๋ฅผ ๋งํน(CAS ์ฌ์ฉ) → pred์ next๋ฅผ curr์ next๋ก ๋ณ๊ฒฝ (CAS ์ฌ์ฉ)
- ๋ฌธ์ ) pred์ curr๋ฅผ ์ ๊ธ ์ ์๋ค.
→ Remove์ ์ ๊ฑฐ๋ฅผ ์๋, ์คํจํ๋ฉด ๋ฌด์ (๋ชจ๋ ๋ฉ์๋๋ฅผ ์์ )
→ ๋ฉ์๋ ํธ์ถ ์ ๋งํน๋ ๋ ธ๋๋ฅผ ์ ๊ฑฐํ๊ณ ์งํ – ์ ๊ฑฐํ๋ฉด์ ๊ฒ์ (๊ฒ์์ ๋ ธ๋์ ์ญ์ ๋ฅผ ๋์์ ํํจ)
[ ๊ตฌํ ์์ ]
- ๋ฉ๋ชจ๋ฆฌ ๋ฆญ์ ํด๊ฒฐ๋ฐฉ๋ฒ
1) Atomic shared_ptr
- (blocking๊ตฌํ) ๋๋ ค, ์ง์ญ๋ณ์ atomic์ด ์๋ shared_ptr ์ฌ์ฉ(ํฌ์ธํฐ update ๋ง์ด ํ๋ฉด X), ํจ์์ const reference
2) stamped pointer
3) EPOCH (Epoch Based Reuse)
4) Hazard Pointer (๋ํ์..)
'๐ค Study > MultiThread' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[05์ฃผ์ฐจ] ๋๊ธฐํ ์ฐ์ฐ & CAS (0) | 2024.04.24 |
---|---|
[04์ฃผ์ฐจ] ๋ฉ๋ชจ๋ฆฌ ์ผ๊ด์ฑ (0) | 2024.04.18 |
[03์ฃผ์ฐจ] ๋ฉํฐ์ฐ๋ ๋ ํ๋ก๊ทธ๋๋ฐ ์ฃผ์์ฌํญ & ์ํธ๋ฐฐ์ ์๊ณ ๋ฆฌ์ฆ (1) | 2024.04.18 |
[02์ฃผ์ฐจ] ๋ฉํฐ์ฝ์ด HW & DataRace (0) | 2024.04.18 |
[01์ฃผ์ฐจB] ๋ฉํฐ์ฝ์ด HW & ๋ฉํฐ์ฐ๋ ๋ํ๋ก๊ทธ๋๋ฐ ์์ (0) | 2024.03.28 |