<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>http://junhoahn.kr/noriwiki/index.php?action=history&amp;feed=atom&amp;title=Michael-Scott_queue</id>
	<title>Michael-Scott queue - 편집 역사</title>
	<link rel="self" type="application/atom+xml" href="http://junhoahn.kr/noriwiki/index.php?action=history&amp;feed=atom&amp;title=Michael-Scott_queue"/>
	<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Michael-Scott_queue&amp;action=history"/>
	<updated>2026-05-19T11:19:57Z</updated>
	<subtitle>이 문서의 편집 역사</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>http://junhoahn.kr/noriwiki/index.php?title=Michael-Scott_queue&amp;diff=1514&amp;oldid=prev</id>
		<title>Ahn9807: 새 문서: 분류: 동시성 프로그래밍  == 개요 == Michael-Scott&#039;s queue는 Lock free를 고려한 큐의 구현이다.  == 기본 원칙 == Treiber&#039;s stack과 마찬가지로, queue에 push, pop할때 변경이 있는지 없는지 확인하고 없을 경우에만 푸쉬,팝을 하는 구조이다.  Pop은 헤드 포인터에, Push는 테일 포인터에 적용된다. 이때 대원칙은 Treiber&#039;s stack과 동일한다.   하나 예외상황은, Tail포인터가...</title>
		<link rel="alternate" type="text/html" href="http://junhoahn.kr/noriwiki/index.php?title=Michael-Scott_queue&amp;diff=1514&amp;oldid=prev"/>
		<updated>2024-05-22T07:01:26Z</updated>

		<summary type="html">&lt;p&gt;새 문서: &lt;a href=&quot;/noriwiki/index.php?title=%EB%B6%84%EB%A5%98:%EB%8F%99%EC%8B%9C%EC%84%B1_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D&quot; title=&quot;분류:동시성 프로그래밍&quot;&gt;분류: 동시성 프로그래밍&lt;/a&gt;  == 개요 == Michael-Scott&amp;#039;s &lt;a href=&quot;/noriwiki/index.php?title=Queue&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Queue (없는 문서)&quot;&gt;queue&lt;/a&gt;는 &lt;a href=&quot;/noriwiki/index.php?title=Lock_free&quot; title=&quot;Lock free&quot;&gt;Lock free&lt;/a&gt;를 고려한 큐의 구현이다.  == 기본 원칙 == &lt;a href=&quot;/noriwiki/index.php?title=Treiber%27s_stack&quot; class=&quot;mw-redirect&quot; title=&quot;Treiber&amp;#039;s stack&quot;&gt;Treiber&amp;#039;s stack&lt;/a&gt;과 마찬가지로, queue에 push, pop할때 변경이 있는지 없는지 확인하고 없을 경우에만 푸쉬,팝을 하는 구조이다.  Pop은 헤드 포인터에, Push는 테일 포인터에 적용된다. 이때 대원칙은 &lt;a href=&quot;/noriwiki/index.php?title=Treiber%27s_stack&quot; class=&quot;mw-redirect&quot; title=&quot;Treiber&amp;#039;s stack&quot;&gt;Treiber&amp;#039;s stack&lt;/a&gt;과 동일한다.   하나 예외상황은, Tail포인터가...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;새 문서&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[분류: 동시성 프로그래밍]]&lt;br /&gt;
&lt;br /&gt;
== 개요 ==&lt;br /&gt;
Michael-Scott&amp;#039;s [[queue]]는 [[Lock free]]를 고려한 큐의 구현이다.&lt;br /&gt;
&lt;br /&gt;
== 기본 원칙 ==&lt;br /&gt;
[[Treiber&amp;#039;s stack]]과 마찬가지로, queue에 push, pop할때 변경이 있는지 없는지 확인하고 없을 경우에만 푸쉬,팝을 하는 구조이다.&lt;br /&gt;
&lt;br /&gt;
Pop은 헤드 포인터에, Push는 테일 포인터에 적용된다. 이때 대원칙은 [[Treiber&amp;#039;s stack]]과 동일한다. &lt;br /&gt;
&lt;br /&gt;
하나 예외상황은, Tail포인터가 Stale할 수 있다는 점이다. 즉, Pushing이 일어난 직후, Tail pointer가 가르키는 pointer는 테일이 아닐 수도 있기 때문이다. 따라서, Michael-Scott&amp;#039;s 큐에서는 테일이 진짜 테일이 아닐 수도 있다. 테일의 정의를 &amp;quot;Head에서 접근 가능한 노드중 하나&amp;quot;로 정의함으로써, 테일에 대한 조건을 Relax하여 정의하게 된다. 나중에 Push하는 상황에서 현재 Tail이 진짜 테일인지 아닌지 확인하여, Tail을 우선 업데이트하고 push하는 식으로 알고리즘이 구현된다.&lt;br /&gt;
&lt;br /&gt;
== 알고리즘 ==&lt;br /&gt;
; POP&lt;br /&gt;
# 만약 Head가 Dummy pointer일 경우 tail pointer를 업데이트 한다. Dummy head를 두는 이유는, empty인 상황에서도 Tail이 특정 노드를 가르키도록 하기 위해서이다.&lt;br /&gt;
# Head pointer를 업데이트 한다. (treiber&amp;#039;s stack과 같은 방식임)&lt;br /&gt;
&lt;br /&gt;
; PUSH&lt;br /&gt;
# 우선 테일을 업데이트 한다.&lt;br /&gt;
# 새로운 테일 포인터를 업데이트 한다.&lt;br /&gt;
# 테일 포인터를 업데이트 한다. 이때 실패해도 괜찮다. 여기서 업데이트를 실패해도 해주는 이유는 Cache적으로 기존에 접근한 테일 포인터를 업데이트 해주는 것이 캐시에 있기 떄문에 좋기 때문이다.&lt;br /&gt;
&lt;br /&gt;
== 예시 ==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=rust&amp;gt;&lt;br /&gt;
 /// Adds `t` to the back of the queue.&lt;br /&gt;
    pub fn push(&amp;amp;self, t: T, guard: &amp;amp;mut Guard) {&lt;br /&gt;
        let mut new = Owned::new(Node {&lt;br /&gt;
            data: MaybeUninit::new(t),&lt;br /&gt;
            next: Atomic::null(),&lt;br /&gt;
        });&lt;br /&gt;
&lt;br /&gt;
        loop {&lt;br /&gt;
            guard.repin();&lt;br /&gt;
&lt;br /&gt;
            // We push onto the tail, so we&amp;#039;ll start optimistically by looking there first.&lt;br /&gt;
            let tail = self.tail.load(Acquire, guard);&lt;br /&gt;
&lt;br /&gt;
            // Attempt to push onto the `tail` snapshot; fails if `tail.next` has changed.&lt;br /&gt;
            let tail_ref = unsafe { tail.deref() };&lt;br /&gt;
            let next = tail_ref.next.load(Acquire, guard);&lt;br /&gt;
&lt;br /&gt;
            // If `tail` is not the actual tail, try to &amp;quot;help&amp;quot; by moving the tail pointer forward.&lt;br /&gt;
            if !next.is_null() {&lt;br /&gt;
                let _ = self&lt;br /&gt;
                    .tail&lt;br /&gt;
                    .compare_exchange(tail, next, Release, Relaxed, guard);&lt;br /&gt;
                continue;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            // looks like the actual tail; attempt to link at `tail.next`.&lt;br /&gt;
            match tail_ref&lt;br /&gt;
                .next&lt;br /&gt;
                .compare_exchange(Shared::null(), new, Release, Relaxed, guard)&lt;br /&gt;
            {&lt;br /&gt;
                Ok(new) =&amp;gt; {&lt;br /&gt;
                    // try to move the tail pointer forward.&lt;br /&gt;
                    let _ = self&lt;br /&gt;
                        .tail&lt;br /&gt;
                        .compare_exchange(tail, new, Release, Relaxed, guard);&lt;br /&gt;
                    break;&lt;br /&gt;
                }&lt;br /&gt;
                Err(e) =&amp;gt; new = e.new,&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /// Attempts to dequeue from the front.&lt;br /&gt;
    ///&lt;br /&gt;
    /// Returns `None` if the queue is observed to be empty.&lt;br /&gt;
    pub fn try_pop(&amp;amp;self, guard: &amp;amp;mut Guard) -&amp;gt; Option&amp;lt;T&amp;gt; {&lt;br /&gt;
        loop {&lt;br /&gt;
            guard.repin();&lt;br /&gt;
&lt;br /&gt;
            let head = self.head.load(Acquire, guard);&lt;br /&gt;
            let next = unsafe { head.deref() }.next.load(Acquire, guard);&lt;br /&gt;
&lt;br /&gt;
            let next_ref = unsafe { next.as_ref() }?;&lt;br /&gt;
&lt;br /&gt;
            // Moves `tail` if it&amp;#039;s stale. Relaxed load is enough because if tail == head, then the&lt;br /&gt;
            // messages for that node are already acquired.&lt;br /&gt;
            let tail = self.tail.load(Relaxed, guard);&lt;br /&gt;
            if tail == head {&lt;br /&gt;
                let _ = self&lt;br /&gt;
                    .tail&lt;br /&gt;
                    .compare_exchange(tail, next, Release, Relaxed, guard);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if self&lt;br /&gt;
                .head&lt;br /&gt;
                .compare_exchange(head, next, Release, Relaxed, guard)&lt;br /&gt;
                .is_ok()&lt;br /&gt;
            {&lt;br /&gt;
                // Since the above `compare_exchange()` succeeded, `head` is detached from `self` so&lt;br /&gt;
                // is unreachable from other threads.&lt;br /&gt;
&lt;br /&gt;
                // SAFETY: `next` will never be the sentinel node, since it is the node after&lt;br /&gt;
                // `head`. Hence, it must have been a node made in `push()`, which is initialized.&lt;br /&gt;
                //&lt;br /&gt;
                // Also, we are returning ownership of `data` in `next` by making a copy of it via&lt;br /&gt;
                // `assume_init_read()`. This is safe as no other thread has access to `data` after&lt;br /&gt;
                // `head` is unreachable, so the ownership of `data` in `next` will never be used&lt;br /&gt;
                // again as it is now a sentinel node.&lt;br /&gt;
                let result = unsafe { next_ref.data.assume_init_read() };&lt;br /&gt;
&lt;br /&gt;
                // SAFETY: `head` is unreachable, and we no longer access `head`. We destroy `head`&lt;br /&gt;
                // after the final access to `next` above to ensure that `next` is also destroyed&lt;br /&gt;
                // after.&lt;br /&gt;
                unsafe { guard.defer_destroy(head) };&lt;br /&gt;
&lt;br /&gt;
                return Some(result);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Ahn9807</name></author>
	</entry>
</feed>