League Of Legends - Link Select [06~08์ฃผ์ฐจ] Non-Blocking ์•Œ๊ณ ๋ฆฌ์ฆ˜ - LIST
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿค“ Study/MultiThread

[06~08์ฃผ์ฐจ] Non-Blocking ์•Œ๊ณ ๋ฆฌ์ฆ˜ - LIST

by GAMEMING 2024. 4. 25.
728x90

 

- 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;
	}
};

 

๊ฒŒ์œผ๋ฅธ ๋™๊ธฐํ™” + shared_ptr

 

 

 : ๋Œ์•„๊ฐ€๋Š”๊ฐ€? 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

 

 

 : ์„ฑ๋Šฅ ๋ฌธ์ œ ๋ฐœ์ƒ

 - 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();
	}
};

 

atomic_shared_ptr

 

 

 : 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 (๋Œ€ํ•™์›..)