<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.158.78&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.158.78&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/217.66.158.78"/>
		<updated>2026-04-25T19:46:23Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%82%D0%B5%D0%BA_%D0%A2%D1%80%D0%B0%D0%B9%D0%B1%D0%B5%D1%80%D0%B0&amp;diff=67100</id>
		<title>Стек Трайбера</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%82%D0%B5%D0%BA_%D0%A2%D1%80%D0%B0%D0%B9%D0%B1%D0%B5%D1%80%D0%B0&amp;diff=67100"/>
				<updated>2018-11-24T09:04:35Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.158.78: запятые и другие незначительные правки&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{В разработке}}&lt;br /&gt;
'''Стек Трайбера''' (англ. ''Treiber Stack'') —  масштабируеммый стек без блокировок (англ. ''lock-free''). Считается, что впервые данный алгоритм был опубликовал R. Kent Treiber&amp;lt;ref&amp;gt;[http://domino.research.ibm.com/library/cyberdig.nsf/0/58319a2ed2b1078985257003004617ef?OpenDocument R. Kent Treiber {{---}} Systems Programming: Coping with Parallelism, 1968]&amp;lt;/ref&amp;gt;. Алгоритм использует примитив &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt; (''compare and set'').&lt;br /&gt;
== Описание ==&lt;br /&gt;
=== Требования к алгоритму ===&lt;br /&gt;
Основное отличие стека Трайбера от однопоточного заключается в том, что несколько потоков имеют доступ к данным в стеке одновременно, а значит, могут удалять и добавлять элементы. Необходимо как-то контролировать процесс взаимодействия потоков. Конечно, это можно было бы сделать, просто блокируя каждую операцию, производимую на стеке. Но такая блокировка уменьшает параллелизм, а значит, уменьшаем масштабируемость программы. Уходя от данной стратегии, разрешим потокам работать одновременно со стеком и потребуем от алгоритма условие неблокируемости.&lt;br /&gt;
=== Lock-free алгоритмы и CAS ===&lt;br /&gt;
Свойство неблокируемости (англ. ''Lock-freedom'') гарантирует прогресс в системе. Для его реализации используется операция &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{{Определение &lt;br /&gt;
|definition=&lt;br /&gt;
'''Сравнение с обменом''' (англ. ''compare and set, compare and swap, CAS'') — атомарная инструкция, сравнивающая значение в памяти с первым аргументом и, в случае успеха, записывающая второй аргумент в память.&lt;br /&gt;
}}&lt;br /&gt;
Ниже представлен псевдокод операции &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt; для целочисленных переменных.&lt;br /&gt;
&lt;br /&gt;
 '''fun''' cas('''int*''' p, '''int''' old, '''int''' new): '''bool'''&lt;br /&gt;
     '''if''' *p != old &lt;br /&gt;
         '''return''' '''false'''&lt;br /&gt;
     *p = new&lt;br /&gt;
     '''return''' '''true'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt;  используется для реализации таких примитивов синхронизации, как ''mutex'' и ''semaphore''. Это своеобразный базовый &amp;quot;кирпичик&amp;quot; для ''Lock-free'' алгоритмов, ведь если &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt; привел к неудаче, то другой поток изменил старое значение. &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt; реализован на уровне атомарных переменных во многих языках программирования.&lt;br /&gt;
&lt;br /&gt;
== Алгоритм == &lt;br /&gt;
&lt;br /&gt;
=== Идеи ===&lt;br /&gt;
Переходя от требований к конкретной реализации, введем следующие условия:&lt;br /&gt;
#Добавлять новый элемент только убедившись, что на момент окончания операции, указатель на голову стека остался тот же. Другими словами, элемент, выбранный нами в качестве &amp;lt;tex&amp;gt;next&amp;lt;/tex&amp;gt;, на момент окончания операции все еще актуален.&lt;br /&gt;
#При удалении элемента, перед его возвратом, нужно быть уверенным, что мы действительно удаляем текущую голову стека и в качестве новой головы предъявляем &amp;lt;tex&amp;gt;H.next&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Структура стека ===&lt;br /&gt;
Как всегда, каждый элемент стека содержит информацию о хранимом значении (&amp;lt;tex&amp;gt;value&amp;lt;/tex&amp;gt;) и указатель на следующий элемент (&amp;lt;tex&amp;gt;next&amp;lt;/tex&amp;gt;). Также имеем указатель на голову стека &amp;lt;tex&amp;gt;H&amp;lt;/tex&amp;gt;, который будем изменять при помощи операции &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt;. Если при этом голова указывает на &amp;lt;tex&amp;gt;null&amp;lt;/tex&amp;gt;, то стек — пуст.&lt;br /&gt;
&lt;br /&gt;
=== Удаление элементов ===&lt;br /&gt;
Запомним, на что указывает голова стека (запишем в локальную переменную &amp;lt;tex&amp;gt;head&amp;lt;/tex&amp;gt;). Значение, которое хранит в себе &amp;lt;tex&amp;gt;head&amp;lt;/tex&amp;gt;, — то, что необходимо будет вернуть. Попробуем переместить голову стеком &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt;ом. Если удалось — вернем &amp;lt;tex&amp;gt;head.value&amp;lt;/tex&amp;gt;. Если нет, то это означает, что с момента начала операции стек был изменен. Поэтому попробуем проделать операцию заново.&lt;br /&gt;
&lt;br /&gt;
=== Добавление элементов ===&lt;br /&gt;
Запомним, куда указывает голова стека (запишем в локальную переменную &amp;lt;tex&amp;gt;head&amp;lt;/tex&amp;gt;). Создадим новый элемент, который хотим добавить в начало стека. Указатель на следующее значение для него — &amp;lt;tex&amp;gt;head&amp;lt;/tex&amp;gt;. Попробуем переместить &amp;lt;tex&amp;gt;H&amp;lt;/tex&amp;gt; на новый элемент, при помощи &amp;lt;tex&amp;gt;CAS&amp;lt;/tex&amp;gt;. Если это удалось — добавление прошло успешно. Если нет, то кто-то другой изменил стек, пока мы пытались добавить элемент. Придется начинать сначала.&lt;br /&gt;
&lt;br /&gt;
== Псевдокод ==&lt;br /&gt;
 '''fun''' pop(): '''Int'''&lt;br /&gt;
     '''while''' ('''true''') &amp;lt;font color=green&amp;gt;//Cas loop&amp;lt;/font&amp;gt;&lt;br /&gt;
       head = H&lt;br /&gt;
       '''if''' (CAS (&amp;amp;H, head, head.next)) &lt;br /&gt;
         '''return''' head.value&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
 '''fun''' push(x: '''Int''')&lt;br /&gt;
     '''while''' ('''true''') &amp;lt;font color=green&amp;gt;//Cas loop&amp;lt;/font&amp;gt;&lt;br /&gt;
       head = H&lt;br /&gt;
       '''if''' (head == null)&lt;br /&gt;
         '''throw''' new EmptyStackException();&lt;br /&gt;
       newHead = Node {value: x, next: head}&lt;br /&gt;
       '''if''' (CAS (&amp;amp;H, head, newHead)) &lt;br /&gt;
         '''return'''&lt;br /&gt;
&lt;br /&gt;
==Примечания==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Алгоритмы_взаимного_исключения]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации==&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Treiber_Stack Wikipedia Treiber {{---}} Stack]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Compare-and-swap Wikipedia {{---}} CAS]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Параллельное программирование]]&lt;/div&gt;</summary>
		<author><name>217.66.158.78</name></author>	</entry>

	</feed>