記憶度
12問
31問
0問
0問
0問
アカウント登録して、解答結果を保存しよう
問題一覧
1
set을 배열이 아닌 링크드리스트로 구현하는 이유는?
최댓값을 모르기 때문이다.
2
성긴 동기화의 장점은?
구현이 쉽다.
3
성긴동기화의 단점은?
성능이 안좋다.
4
성긴 동기화를 사용하면 data race는 100% 사라진다. ( O / X )
O
5
왼쪽 위에부터 빈칸을 채우시오.
왼쪽 glock.lock(); glock.unlock(); glock.unlock(); 오른쪽 glock.lock(); glock.unlock(); glock.unlock(); 아래 glock.lock(); glock.unlock(); glock.unlock();
6
이것은 무슨 동기화인가?
성긴동기화
7
pred = &head;가 lock 밖에 있는 이유는?
read only 메모리이기 때문에 data race가 아니기 때문이다.
8
new/delete는 data race가 없다. ( O / X )
O
9
멀티스레드 실무에서 new/delete를 잘 사용하지 않는다. 이유는?
내부적으로 locking이 구현되어 있기 때문이다.
10
세밀한 동기화는 성긴 동기화의 어떤 점을 보완하고자 나왔는가?
list 전체를 잠그는 것이 아니라 노드 개별로 잠궈서 병렬성을 높이기 위해 나온 것이다.
11
세밀한 동기화에서는 node의 ( )를 변경할 경우에는 반드시 lock()을 얻은 후 변경해야 한다.
next field
12
세밀한 동기화의 주의점은?
Add()와 Remove() 시점의 pred, curr가 가리키는 노드는 locking이 되어 있어야 한다., head부터 node 이동을 할 때, lock을 잠그면서 이동해야 한다.
13
세밀한 동기화를 통해 발견한 것은?
스레드 개수가 늘어날수록 빨라진다. 물론 어느정도 되면 다시 느려진다.
14
세밀한 동기화는 어떤 곳이 바틀넥이 되는가?
head
15
성긴 동기화 영어로 쓰시오.
coarse-grained synchronization
16
세밀한 동기화를 영어로 쓰시오.
fine-grained synchronization
17
낙천적인 동기화를 영어로 쓰시오.
optimistic synchronization
18
게으른 동기화를 영어로 쓰시오.
lazy synchronization
19
비멈춤 동기화를 영어로 쓰시오.
nonblocking synchronization
20
주석에 답하시오.
Add() 1: prev->lock(); 2: curr->lock(); 3: prev->unlock(); 4: curr->lock(); 5: prev->unlock(); 6: curr->unlock(); 7: prev->unlock(); 8: curr->unlock(); Remove() 1: prev->lock(); 2: curr->lock(); 3: prev->unlock(); 4: curr->lock(); 5: prev->unlock(); 6: curr->unlock(); 7: prev->unlock(); 8: curr->unlock(); Contains() 1: prev->lock(); 2: curr->lock(); 3: prev->unlock(); 4: curr->lock(); 5: prev->unlock(); 6: curr->unlock(); 7: prev->unlock(); 8: curr->unlock();
21
성긴 동기화와 세밀한 동기화 중 어떤 것이 더 성능이 좋은가?
성긴 동기화
22
세밀한 동기화의 성능 저하의 원인은?
lock(), unlock()이 너무 빈번하다.
23
세밀한 동기화는 리스트가 ( ) 경우 성능이 매우 떨어진다.
길어지는
24
낙천전 동기화는 세밀한 동기화의 어떤 것을 보완하기 위해 나왔나?
잠금의 획득과 해제가 너무 빈번하여 이동 시 잠금을 하지 않지 않기 위해 나온 아이디어이다.
25
낙천적 동기화는 Remove()한 노드를 ( )하지 않는다.
delete
26
낙천적 동기화에는 ( ) 검사를 추가한다.
validation 조건
27
낙천적 동기화에서 제거된 노드를 delete하지 않는 이유는?
재사용되면서 어떻게 사용될지 모르기 때문이다.
28
validation 조건 검사에서 하는 것은?
잠겨진 pred와 curr가 제거되지 않았는지, pred와 curr 사이에 다른 노드가 끼어들지 않았는지
29
validation 조건 검사에서 pred와 curr 사이에 다른 노드가 끼어들지 않은 것을 어떻게 확인할 수 있는가?
pred->next == curr 이면 다른 노드가 끼어들지 않은 것이다.
30
volidation에서 다시 돌 때 다른 스레드가 pred, curr를 삭제하거나 중간에 노드를 끼울 수 있는 확률은? 이유는?
전혀 없다. locking을 하고 검사를 하기 때문이다.
31
validate()에서 pred와 curr가 리스트에 존재하는지 어떻게 확인할 수 있는가?
다시 처음부터 검색해서 원래 pred, curr로 다시 올 수 있는지 확인한다.
32
낙천적 동기화 알고리즘의 문제점은?
다른 스레드들이 pred와 curr를 계속 수정하는 경우 계속 재시도를 하면서 기아를 겪을 수 있다.
33
낙천적 동기화에서 기아가 발생할 확률은 리스트의 길이가 길어질수록 확률이 올라간다. ( O / X )
X
34
빈칸에 알맞은 것을 적으시오.
add() validate(pred, curr) false true contains() validate(pred, curr) curr.key == key
35
성긴 동기화는 스레드가 늘어남에 따라 성능 변화가 있다. ( O / X )
X
36
낙천적인 동기화가 싱글 스레드에서도 성긴 동기화보다 2배 느린 이유는?
링크드 리스트에서 성능에 가장 영향에 미치는 것은 검색이다. 성긴 동기화는 한 번 검색하는데, 낙천적 동기화는 처음에 한 번 검색하고 validate 하면서 한 번 더 검색하기 때문에 2배 느리다.
37
낙천적인 동기화에서 발견한 것은?
스레드 개수가 늘어남에 따라 싱글 스레드보다 성능이 더 좋아지는 것을 확인했다.
38
게으른 동기화는 낙천적 동기화의 어떤 부분을 보완하고자 나왔는가?
낙천적 동기화는 코어의 개수가 많지 않으면 성능이 좋지 않다. 이것을 개선하고자 나온 것이 게으른 동기화이다.
39
게으른 동기화의 핵심 아이디어는?
validate()가 노드를 처음부터 다시 순회하지 않고 수행
40
게으른 동기화에서 pred와 curr의 잠금은 여전히 필요하다. ( O / X )
O
41
contains는 ( )이기 때문에 wait-free 알고리즘으로 변환할 수 있다.
read-only
42
게으른 동기화에서 추가된 것은?
marked 필드
43
게으른 동기화에서 marking은 실제 제거보다 반드시 ( ) 수행한다.
먼저
44
빈칸을 채우시오.
node == pred pred.next == curr node = node.next
45
빈칸을 채우시오.
validate() !pred.marked && !curr.marked && pred.next == curr contains() curr = curr.next; curr.key == key && !curr.marked
46
게으른 동기화의 remove()이다. 빈칸을 채우시오.
curr.marked = true;
47
게으른 동기화가 제대로 돌아가는 것은 어떠한 명제로 인해서인가?
marking 되어 있지 않은 모든 node는 실제 리스트에 존재하는 살아있는 node이다. 해당 명제가 참이기 때문이다.
48
게으른 알고리즘은 넌블럭킹 알고리즘이다. ( O / X )
X
49
게으른 동기화는 싱글 스레드에서 돌리는 것보다 빨라지는가?
빨라진다. 스레드가 하나일 때는 더 느리지만 이 세상에 싱글코어 컴퓨터는 없다.
50
게으른 동기화의 단점은?
블럭킹 알고리즘이다., 메모리 릭이 있다.
51
게으른 동기화에서 메모리 릭을 없애기 위해 그냥 delete를 하면 안되는 이유는?
재사용하면서 오동작할 수 있기 때문이다.
52
게으른 동기화에서 메모리 릭을 해결하기 위해서는 언제 delete를 해야 하는가?
아무도 remove된 node를 가리키지 않을 때, remove 시점에서 중복실행 중인 모든 method의 호출이 종료되었을 때
53
shared_ptr은 reference counter 증감을 atomic하게 구현한다. ( O / X )
O
54
shared_ptr이 메모리 해제를 어떻게 자동으로 하는지에 대해 설명하시오.
shared_ptr을 생성할 때 reference counter도 같이 할당해서 이 카운터를 증가하고 감소하면서 0이 되면 해제한다.
55
shared_ptr 게으른 동기화가 제대로 동작하지 않는 이유는?
shared_ptr 객체를 load, store하는 것이 atomic이 아니기 때문이다.
56
shared_ptr 게으른 동기화는 모든 스레드 개수에서 잘 돌아가는가?
싱글 스레드에서만 잘 돌아가고 멀티스레드에서는 죽는다.
57
성긴 동기화, 세밀한 동기화, 낙천적 동기화, 게으른 동기화 중 싱글 스레드에서 성능이 좋은 것 순으로 나열하시오.
성긴 동기화, 게으른 동기화, 낙천전 동기화, 세밀한 동기화
58
성긴 동기화, 세밀한 동기화, 낙천적 동기화, 게으른 동기화 중 멀티스레드로 갈수록 성능 향상에서의 좋은 것 순으로 나열하시오.
게으른 동기화, 낙천적 동기화, 성긴동기화, 세밀한 동기화
59
atomic shared_ptr은 잘 돌아가는가?
잘 돌아간다. 하지만 성능이 엉망진창이다.
60
멀티스레드에서 shared_ptr은 절대 사용하면 안된다. ( O / X )
X
61
Atomic shared_ptr의 성능이 좋지 않은 이유는?
내부적으로 mutex를 사용하고 또한 하나의 lock으로 실행되기 때문이다.
62
멀티스레드에서 성능이 필요 없는 곳에 shared_ptr을 사용하고 싶다면 어떤 것을 사용해야 하는가?
local atomic shared ptr
63
stl은 멀티스레드에서 사용해도 된다. ( O / X )
X
64
lock을 사용하지 않으면 non-blocking 알고리즘이다. ( O / X )
X
65
wait-free 알고리즘이라도 lock-free 알고리즘이 아닐 수 있다. ( O / X )
X
66
해당 코드를 넌블럭킹으로 바꿔라.
if (dataReady == false) return false; temp = g_data;
67
CAS를 사용하면 모든 싱글스레드 알고리즘들을 lock-free 알고리즘으로 변환할 수 있다. ( O / X )
O
68
해당 코드를 넌블럭킹으로 고쳐라.
while (true) { int old_sum = sum; int new_sum = old_sum + 2; if (true == CAS(&sum, old_sum, new_sum)) break; }
69
CAS를 사용하면 lock-free 알고리즘이 되는데 어려운 이유는?
CAS는 2개의 변수에 동시에 적용할 수 없기 때문이다. 따라서 CAS를 두 번 나누어서 해주어야 하는데 그러면 그 사이에 다른 스레드가 끼어들 수 있다. 난이도가 상승한다.
70
게으른 동기화가 넌블럭킹으로 가는 지름길인 이유는?
critical section이 충분히 짧아졌기 때문이다.
71
비멈춤 동기화 Add의 구현에서 다른 스레드가 *pred를 Remove하면 어떻게 해야 하는가?
pred의 marking을 확인하면서 변경해야 한다.
72
비멈춤 동기화 Add의 구현에서 다른 스레드가 *pred, *curr 사이에 새로운 노드를 끼워 넣으면 어떻게 해야 하는가?
pred와 next가 curr인 것을 확인하면서 변경해야 한다.
73
비멈춤 동기화에서 double CAS를 사용하지 못하여서 어떠한 방법을 사용했는가?
한 장소에 주소와 marking을 동시에 저장했다.
74
double CAS처럼 사용하기 위한 한 장소에 주소와 marking을 동시에 저장하는 것은 어떻게 가능한가?
우리의 컴퓨터가 64비트라고 그 비트를 다 사용하지 않는다. 이 중에 안 쓰는 비트를 사용하여 가능하게 한다.
75
비멈춤 동기화에서 Remove 시 제거를 시도하고 실패했을 때를 대비해 어떻게 정책을 수정했는가?
마킹이되었지만 remove되지 않은 노드가 있는 있을 수 있다.
76
비멈춤 코드의 find()이다. 빈칸을 채우시오.
pred.next.comparedAndSet(curr, succ, false, false);
77
비멈춤 동기화의 add(), remove()의 빈칸을 채우시오.
add() find(head, key) new AtomicMarkableReference(curr, false) pred.next.compareAndSet(curr, node, false, false) remove() find(head, key) curr.next.attemptMark(succ, true) pred.next.compareAndSet(curr, succ, false, false)
78
우리가 만든 lock-free 알고리즘에 shared_ptr을 사용할 수 없는 이유는?
그냥 포인터가 아닌 합성 포인터를 사용했기 때문이다.
79
EPOCH의 장점과 단점은?
성능이 좋다. 메모리 재사용에 stopation이 생길 수 있다.
80
Lock free free list 기법을 발전 시킨 알고리즘은?
EPOCH
81
EPOCH에서 chrono를 사용하지 않고 Epoch counter를 사용하는 이유는?
Epoch를 사용하기에 정밀하지 않다. 읽고 쓰는 오버헤드가 크다. 데이터 사이즈가 크다.
82
EPOCH에서 'Thread Epoch Counter[My_Thread_ID] = 0;' 해당 코드가 의미하는 것은?
검색 대상이 아니다. 일종의 최적화 시켜주는 코드
83
EPOCH의 단점은?
어느 한 스레드의 thread epoch counter가 증가하지 않을 경우 메모리 릭이나 다름 없다.
84
EPOCH에는 각 스레드들은 자신만의 memory pool(free list)을 관리한다. ( O / X )
O