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