Очередь Майкла и Скотта — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Структура очереди)
(Идея реализации)
Строка 28: Строка 28:
 
Для удаления элемента необходимо переместить указатель <tex>H</tex> на следующую в списке вершину.
 
Для удаления элемента необходимо переместить указатель <tex>H</tex> на следующую в списке вершину.
  
  '''def''' pop(): '''T'''
+
  '''def''' pop(): '''Int'''
 
     if (H.next == null):
 
     if (H.next == null):
 
         '''throw''' new EmptyException()
 
         '''throw''' new EmptyException()
Строка 38: Строка 38:
 
Создадим новый узел списка, и добавим его в конец очереди.  
 
Создадим новый узел списка, и добавим его в конец очереди.  
  
  '''def''' push(x: '''T'''):
+
  '''def''' push(x: '''Int'''):
     newTail = new Node<'''T'''>(x, new AtomicReference<Node<T>>(null))
+
     newTail = new Node(x, new AtomicReference<Node>(null))
 
     T.next = newTail <font color=green>//Добавление новой вершины в очередь</font>
 
     T.next = newTail <font color=green>//Добавление новой вершины в очередь</font>
 
     T = T.next <font color=green>//Изменение хвоста списка</font>
 
     T = T.next <font color=green>//Изменение хвоста списка</font>

Версия 17:48, 1 октября 2018

Эта статья находится в разработке!

Очередь Майкла и Скотта (Michael-Scott Queue) - алгоритм построения lock-free очереди. Впервые был предложен Maged M. Michael и Michael L. Scot в статье [1].

Структура очереди

Очередь моделируется с помощью односвязного списка. Каждый элемент списка ([math]Node[/math]) содержит ссылку на хранимые в нём данные и указатель на следующий элемент списка (который можно менять атомарно).

case class Node(val data: Int, val next: AtomicReference<Node>)

Если узел [math]node[/math] является последним в списке, то его [math]next[/math] указывает на [math]null[/math].

Сама очередь состоит из двух указателей: на голову [math]H[/math] и на хвост [math]T[/math], которые можно менять атомарно. Удаление из очереди происходит со стороны головы, добавление - со стороны хвоста.

Узел списка, на который указывает [math]H[/math], является фиктивным (dummy). Данные, хранимые в этом узле, не имеют значения. Изначально очередь состоит из одного dummy-элемента, на который указывают [math]T[/math] и [math]H[/math].

class Queue
    dummy = new Node(null, new AtomicReference<Node>(null))
    head = new AtomicReference<Node>(dummy)
    tail = new AtomicReference<Node>(dummy)

// TODO; картинка

Будем поддерживать следующий инвариант: в нашей очереди [math]H[/math] указывает на узел, находящийся не правее узла, на который указывает [math]T[/math]

Идея реализации

Удаление элемента

Для удаления элемента необходимо переместить указатель [math]H[/math] на следующую в списке вершину.

def pop(): Int
    if (H.next == null):
        throw new EmptyException()
    H = H.next
    return H.data //H - новый фиктивный элемент

Добавление элемента

Создадим новый узел списка, и добавим его в конец очереди.

def push(x: Int):
    newTail = new Node(x, new AtomicReference<Node>(null))
    T.next = newTail //Добавление новой вершины в очередь
    T = T.next //Изменение хвоста списка

Примечания

Источники информации

  • Maurice Herliny & Nir Shavit - The Art of Multiprocessor programming, стр 230