Очередь Майкла и Скотта — различия между версиями
(→Структура очереди) |
|||
| Строка 5: | Строка 5: | ||
Очередь моделируется с помощью односвязного списка. Каждый элемент списка (<tex>Node</tex>) содержит ссылку на хранимые в нём данные и указатель на следующий элемент списка (который можно менять атомарно). | Очередь моделируется с помощью односвязного списка. Каждый элемент списка (<tex>Node</tex>) содержит ссылку на хранимые в нём данные и указатель на следующий элемент списка (который можно менять атомарно). | ||
| − | '''case class''' Node<T>('''val''' data: T, '''val''' next: AtomicReference<Node<T>>) | + | '''case class''' Node<'''T'''>('''val''' data: '''T''', '''val''' next: AtomicReference<Node<'''T'''>>) |
Если узел <tex>node</tex> является последним в списке, то его <tex>next</tex> указывает на <tex>null</tex>. | Если узел <tex>node</tex> является последним в списке, то его <tex>next</tex> указывает на <tex>null</tex>. | ||
| Строка 13: | Строка 13: | ||
Узел списка, на который указывает <tex>H</tex>, является фиктивным (''dummy''). Данные, хранимые в этом узле, не имеют значения. Изначально очередь состоит из одного ''dummy''-элемента, на который указывают <tex>T</tex> и <tex>H</tex>. | Узел списка, на который указывает <tex>H</tex>, является фиктивным (''dummy''). Данные, хранимые в этом узле, не имеют значения. Изначально очередь состоит из одного ''dummy''-элемента, на который указывают <tex>T</tex> и <tex>H</tex>. | ||
| − | '''class''' Queue<T> | + | '''class''' Queue<'''T'''> |
| − | dummy = new Node(null, new AtomicReference<Node>(null)) | + | dummy = new Node<'''T'''>(null, new AtomicReference<Node>(null)) |
| − | head = new AtomicReference<Node>(dummy) | + | head = new AtomicReference<Node<'''T'''>>(dummy) |
| − | tail = new AtomicReference<Node>(dummy) | + | tail = new AtomicReference<Node<'''T'''>>(dummy) |
// TODO; картинка | // TODO; картинка | ||
Будем поддерживать следующий инвариант: в нашей очереди <tex>H</tex> указывает на узел, находящийся не правее узла, на который указывает <tex>T</tex> | Будем поддерживать следующий инвариант: в нашей очереди <tex>H</tex> указывает на узел, находящийся не правее узла, на который указывает <tex>T</tex> | ||
| + | |||
| + | ==Идея реализации== | ||
| + | |||
| + | === Удаление элемента === | ||
| + | |||
| + | Для удаления элемента необходимо переместить указатель <tex>H</tex> на следующую в списке вершину. | ||
| + | |||
| + | '''def''' pop(): '''T''' | ||
| + | if (H.next == null): | ||
| + | '''throw''' new EmptyException() | ||
| + | H = H.next | ||
| + | return H.data <font color=green>H - новый фиктивный элемент</font> | ||
| + | |||
| + | === Добавление элемента === | ||
==Примечания== | ==Примечания== | ||
Версия 17:38, 1 октября 2018
Очередь Майкла и Скотта (Michael-Scott Queue) - алгоритм построения lock-free очереди. Впервые был предложен Maged M. Michael и Michael L. Scot в статье [1].
Содержание
Структура очереди
Очередь моделируется с помощью односвязного списка. Каждый элемент списка () содержит ссылку на хранимые в нём данные и указатель на следующий элемент списка (который можно менять атомарно).
case class Node<T>(val data: T, val next: AtomicReference<Node<T>>)
Если узел является последним в списке, то его указывает на .
Сама очередь состоит из двух указателей: на голову и на хвост , которые можно менять атомарно. Удаление из очереди происходит со стороны головы, добавление - со стороны хвоста.
Узел списка, на который указывает , является фиктивным (dummy). Данные, хранимые в этом узле, не имеют значения. Изначально очередь состоит из одного dummy-элемента, на который указывают и .
class Queue<T>
dummy = new Node<T>(null, new AtomicReference<Node>(null))
head = new AtomicReference<Node<T>>(dummy)
tail = new AtomicReference<Node<T>>(dummy)
// TODO; картинка
Будем поддерживать следующий инвариант: в нашей очереди указывает на узел, находящийся не правее узла, на который указывает
Идея реализации
Удаление элемента
Для удаления элемента необходимо переместить указатель на следующую в списке вершину.
def pop(): T
if (H.next == null):
throw new EmptyException()
H = H.next
return H.data H - новый фиктивный элемент
Добавление элемента
Примечания
Источники информации
- Maurice Herliny & Nir Shavit - The Art of Multiprocessor programming, стр 230