SlideShare una empresa de Scribd logo
1 de 64
Descargar para leer sin conexión
Параллельное программирование


       Роман Елизаров, 2009
      elizarov@devexperts.com
Взаимное исключение


• Взаимное исключение (Mutual Exclusion)
• Отсутствие блокировки (Freedom from Deadlock)
• Отсутствие голодания (Freedom from Starvation)

  run() {
    int i = getCurrentThreadID();
    while (true) {
      nonCriticalSection();
      lock(i);
      criticalSection();
      unlock(i);
    }
  }
Взаимное исключение, попытка 1

 boolean want[2];

 lock(int i) {
   want[i] = true;
   while (want[1 – i]); // wait
 }

 unlock(int i) {
   want[i] = false;
 }
Взаимное исключение, попытка 2

 int victim;

 lock(int i) {
   victim = i;
   while (victim == i); // wait
 }

 unlock(int i) {
 }
Взаимное исключение, алгоритм Петерсона

 boolean want[2];
 int victim;

 lock(int i) {
   want[i] = true;
   victim = i;
   while (want[1 – i] && victim == i); // wait
 }

 unlock(int i) {
   want[i] = false;
 }
Взаимное исключение, алгоритм Петерсона
для N потоков
 int level[N];
 int victim[N];

 lock(int i) {
   for (int j = 1; j < N; j++) {
     level[i] = j;
     victim[j] = i;
     while exists k != i :
       level[k] >= j && victim[j] == i; // wait
 }

 unlock(int i) {
   level[i] = 0;
 }
Честность


• Отсутствие голодания
• Линейное ожидание, квадратичное ожидание и т.п.
• Первым пришел, первым обслужен (FCFS – First Come First
  Served)


 lock() {
     DoorwaySection(); // wait-free code
     WaitingSection();
 }
Взаимное исключение, алгоритм Лампорта
(алгоритм булочника – вариант 1)
 boolean want[N]; // init with false
 Label label[N]; // init with 0

 lock(int i) {
   want[i] = true;
   label[i] = max(label[0], …, label[N-1]) + 1;
   while exists k != i :
     want[k] && (label[k], k) < (label[i], i);
 }

 unlock(int i) {
   want[i] = false;
 }
Взаимное исключение, алгоритм Лампорта
(алгоритм булочника – вариант 2)
 boolean choosing[N]; // init with false
 Label label[N];      // init with inf

 lock(int i) {
   choosing[i] = true;
   label[i] = max(label[0], …, label[N-1]) + 1;
   choosing[i] = false;
   while exists k != i :
     choosing[k] || (label[k], k) < (label[i], i);
 }

 unlock(int i) {
   label[i] = inf;
 }
Разделяемые объекты


• Корректность реализации объекта
   - Тихая согласованность (Quiescent consistency)
   - Последовательная согласованность (Sequential consistency)
   - Линеаризуемость (Linearizability)
• Прогресс
   - Без помех (Obstruction-free)
   - Без блокировок (Lock-free)
   - Без ожидания (Wait-free)
Регистры


• Разделяемые регистры – базовый объект для общения
  потоков между собой


 interface Register<T> {
   T read();
   void write(T val);
 }
Классификация регистров


• Безопасные (safe), регулярные (regular), атомарные (atomic)
• Один читатель, много читателей (SR, MR)
• Один писатель, много писателей (SW, MW)
• Булевские значение, множественные значения

• Самый примитивный регистр – Safe SRSW Boolean register
• Самый сложный регистр – Atomic MRMW M-Valued register
Построение регистров


• Будем строить более сложные регистры из более простых без
  ожиданий (wait-free образом).
   - Safe SRSW Boolean register
   - Regular SRSW Boolean register
   - Regular SRSW M-Valued register
   - Atomic SRSW M-Valued register
   - Atomic MRSW M-Valued register
   - Atomic MRMW M-Valued register
Атомарный снимок состояния N регистров


• Набор SW атомарных регистров (по регистру на поток)
• Любой поток может вызвать scan() чтобы получить снимок
  состояния всех регистров
• Методы должны быть атомарными (линеаризуемыми)

 interface Snapshot<T> {
   void update(int i, T val);
   T[] scan();
 }
Атомарный снимок состояния N регистров,
без блокировок (lock free)
 // каждый регистр хранит версию “version”
 (T val, Label version) register[N];

 void update(int i, T val) { // wait-free
   register[i] = (val, register[i].version+1);
 }

 T[] scan() { // obstruction-free
   (T, Label)[] old = copyOf(register); // with loop
   while (true) {
     (T, Label)[] cur = copyOf(register);
     if (equal(old, cur)) return cur.val;
                     else old = cur;
   }
 }
Атомарный снимок состояния N регистров,
без ожидания (wait-free) – update
 // каждый регистр так же хранит копию снимка “snap”
 (T val, Label version, T[] snap) register[N];

 void update(int i, T val) { // wait-free
   T[] snap = scan();
   register[i] = (val, register[i].version+1, snap);
 }
Атомарный снимок состояния N регистров,
без ожидания (wait-free) – scan
 T[] scan() { // wait-free, O(N^2) time
   (T, Label, T[])[] old = copyOf(register);
   boolean updated[N];
   loop: while (true) {
     (T, Label, T[])[] cur = copyOf(register);
     for (int j = 0; j < N; j++)
       if (cur[j].version != old[j].version)
         if (updated[j]) return cur[j].snap;
         else {
           updated[j] = true;
           old = cur; continue loop;
         }
     return cur.val;
   }
 }
Консенсус


• Согласованность (consistent): все потоки должны вернуть одно
  и то же значение из метода decide
• Обоснованность (valid): возвращенное значение было
  входным значением какого-то из потоков

 interface Consensus<T> {
   T decide(T val);
 }
Консенсусное число


• Если с помощью класса объектов C можно реализовать
  консенсусный протокол без ожидания (wait-free) для N потоков
  (и не больше), то говорят что у класса C консенсусное число
  равно N.
• ТЕОРЕМА: Атомарные регистры имеют консенсусное число 1.
   - Т.е. с помощью атомарных регистров даже 2 потока не могут
     придти к консенсусу без ожидания (докажем от противного) для
     для 2-х возможных значений при T = {0, 1}
   - С ожиданием задача решается очевидно (с помощью любого
     алгоритма взаимного исключения).
Определения и леммы для любых классов
объектов

• Определения и концепции:
   - Рассматриваем дерево состояния, листья – конечные состояния
     помеченные 0 или 1 (в зависимости от значения консенсуса).
   - x-валентное состояние системы (x = 0,1) – консенсус во всех
     нижестоящих листьях будет x.
   - Бивалентное состояние – возможен консенсус как 0 так и 1.
   - Критическое состояние – такое бивалентное состояние, все дети
     которого одновалентны.
• ЛЕММА: Существует начальное бивалентное состояние.
• ЛЕММА: Существует критическое состояние.
Доказательство для атомарных регистров


• Рассмотрим возможные пары операций в критическом
  состоянии:
   - Операции над разными регистрами – коммутируют.
   - Два чтения – коммутируют.
   - любая операция + Запись – состояние пишущего потока не
     зависит от порядка операций.
Read-Modify-Write регистры


• Для функции или класса функций F(args): T -> T
   - getAndSet (exchange), getAndIncrement, getAndAdd и т.п.
   - get (read) это тоже [тривиальная] RMW операция для F == id.


 сlass RMWRegister<T> {
   private T val;
   T getAndF(args…) atomic {
     T old = val;
     val = F(T, args);
     return old;
   }
 }
Нетривиальные RMW регистры


• Консенсусное число нетривиального RMW регистра >= 2.
   - Нужно чтобы была хотя бы одна «подвижная» точка функции F,
     например F(v0) = v1 != v0.
 T proposed[2];
 RMWRegister rmw; // начальное значение v0

 T decide(T val) {
   int i = myThreadId(); // i = 0,1 – номер потока
   proposed[i] = val;
   if (rmw.getAndF() == v0) return proposed[i];
                       else return proposed[1 – i];
 }
Common2 RMW регистры


• Определения
  - F1 и F2 коммутируют если F1(F2(x)) == F2(F1(x))
  - F1 перезаписывает F2 если F1(F2(x)) == F1(x)
  - Класс С RMW регистров принадлежит Common2, если любая
    пара функций либо коммутирует, либо одна из функций
    перезаписывает другую.
• ТЕОРЕМА: Нетривиальный класс Common2 RMW регистров
  имеет консенсусное число 2.
  - Третий поток не может отличить глобальное состоянием при
    изменения порядка выполнения коммутирующих или
    перезаписывающих операций в критическом состоянии.
Универсальные объекты


• Объект с консенсусный числом бесконечность называется
  универсальным объектом.
   - По определению, с помощью него можно реализовать
     консенсусный протокол для любого числа потоков.
• Пример: compareAndSet aka testAndSet (возвращает boolean),
  compareAndExchange (возвращает старое значение – RMW)

 private T x;
 boolean compareAndSet(T val, T expected) atomic {
   if (x == expected) { x = val; return true; }
                 else return false;
 }
compareAndSet (CAS) и консенсус

// реализация консенсусного протокола через CAS+GET
T decide(T val) {
  if (compareAndSet(val, INITIAL))
          return val;
    else return get();
}

// реализация консенсусного протокола через CMPXCHG
T decide(T val) {
  T old = compareAndExchange(val, INITIAL);
  if (old == INITIAL)
          return val;
    else return old;
}
Универсальность консенсуса


• ТЕОРЕМА: Любой последовательный объект можно
  реализовать без ожидания (wait-free) для N потоков используя
  консенсусный протокол для N объектов.
   - Следствие1: С помощью любого класса объектов с консенсусным
     числом N можно реализовать любой объект с консенсусным
     числом <= N.
   - Следствие2: С помощью универсального объекта можно
     реализовать любой объект.
Иерархия объектов


 Консенсусное   Объект
 число
 1              Атомарные регистры, снимок состояния нескольких
                регистров
 2              getAndSet (атомарный обмен), getAndAdd, очередь,
                стэк
 m              Атомарная запись m регистров из m(m+1)/2
                регистров
 ∞              compareAndSet, LoadLinked/StoreConditional
Многопоточные (Thread-Safe) объекты
(алгоритмы и структуры данных) на практике

• Многопоточный объект включает в себя синхронизацию
  потоков (блокирующую или не блокирующую), которая
  позволяет его использовать из нескольких потоков
  одновременно без дополнительной внешней синхронизации
   - Специфицируется через последовательное поведение
   - По умолчанию требуется линеаризуемость операций (более
     слабые формы согласованности – редко)
   - Редко удается реализовать все операции без ожидания (wait-
     free). Часто приходится идти на компромиссные решения.
• ВНИМАНИЕ: Пока пишем псевдокод. Доведение его до
  реального кода будем обсуждать отдельно.
Разные подходы к синхронизации потоков при
работе с общей структурой данных

• Типы синхронизации:
   - Грубая (Coarse-grained) синхронизация
   - Тонкая (Fine-grained) синхронизация
   - Оптимистичная (Optimistic) синхронизация
   - Ленивая (Lazy) синхронизация
   - Неблокирующая (Nonblocking) синхронизация
• Проще всего для списочных структур данных (с них и начнем),
  хотя на практике массивы работают существенно быстрей
Пример: Множество на основе односвязного
списка

• ИНВАРИАНТ: node.key < node.next.key


 class Node {
     int key;
     T item;
     Node next;
 }

 // Пустой список состоит их 2-х граничных элементов
 Node head = new Node(Integer.MIN_VALUE, null);
 head.next = new Node(Integer.MAX_VALUE, null);
Грубая синхронизация


• Обеспечиваем взаимное исключение всех операций через
  общий Mutex lock.
Грубая синхронизация: поиск

 boolean contains(int key) {
     lock.lock();
     try {
         Node curr = head;
         while (curr.key < key) {
             curr = curr.next;
         }
         return key == curr.key;
     } finally { lock.unlock(); }
 }
Грубая синхронизация: добавление

 boolean add(int key, T item) {
     lock.lock();
     try {
         Node pred = head, curr = pred.next;
         while (curr.key < key) {
             pred = curr; curr = curr.next;
         }
         if (key == curr.key) return false; else {
             Node = new Node(key, item);
             node.next = curr; pred.next = node;
             return true;
         }
     } finally { lock.unlock(); }
 }
Грубая синхронизация: удаление

 boolean remove(int key, T item) {
     lock.lock();
     try {
         Node pred = head, curr = pred.next;
         while (curr.key < key) {
             pred = curr; curr = curr.next;
         }
         if (key == curr.key) {
             pred.next = curr.next;
             return true;
         else {
             return false;
         }
     } finally { lock.unlock(); }
 }
Тонкая синхронизация


• Обеспечиваем синхронизацию через взаимное исключение на
  каждом элементе.
• При любых операциях одновременно удерживаем блокировку
  текущего и предыдущего элемента (чтобы не утерять
  инвариант pred.next == curr).
Тонкая синхронизация: добавление

 Node pred = head; pred.lock();
 Node curr = pred.next; curr.lock();
 try {
     while (curr.key < key) {
         pred.unlock(); pred = curr;
         curr = curr.next; curr.lock();
     }
     if (key == curr.key) return false; else {
         Node = new Node(key, item);
         node.next = curr; pred.next = node;
         return true;
     }
 } finally { curr.unlock(); pred.unlock(); }
Оптимистичная синхронизация


• Ищем элемент без синхронизации (оптимистично предполагая
  что никто не помешает), но перепроверяем с синхронизацией
   - Если перепроверка обломалась, то начинаем операцию заново
• Имеет смысл только если обход структуры дешев и быстр, а
  обход с синхронизацией медленный и дорогой
Оптимистичная синхронизация: поиск

 retry: while(true) {
     Node pred = head, curr = pred.next;
     while (curr.key < key) {
         pred = curr; curr = curr.next;
     }
     pred.lock(); curr.lock();
     try {
         if (!validate(pred, curr)) continue retry;
         return curr.key == key;
     } finally { curr.unlock(); pred.unlock(); }
 }
Оптимистичная синхронизация: валидация

 boolean validate(Node pred, Node curr) {
     Node node = head;
     while (node.key <= pred.key) {
         if (node == pred)
             return pred.next == curr;
         node = node.next;
     }
     return false;
 }
Оптимистичная синхронизация: добавление

 retry: while(true) {
     Node pred = head, curr = pred.next;
     while (curr.key < key) {
         pred = curr; curr = curr.next;
     }
     pred.lock(); curr.lock();
     try {
         if (!validate(pred, curr)) continue retry;
         if (curr.key == key) return false; else {
             Node = new Node(key, item);
             node.next = curr; pred.next = node;
             return true;
         }
     } finally { curr.unlock(); pred.unlock(); }
 }
Оптимистичная синхронизация: удаление

 retry: while(true) {
     Node pred = head, curr = pred.next;
     while (curr.key < key) {
         pred = curr; curr = curr.next;
     }
     pred.lock(); curr.lock();
     try {
         if (!validate(pred, curr)) continue retry;
         if (curr.key == key) {
             pred.next = curr.next;
             return true;
         } else return false;
     } finally { curr.unlock(); pred.unlock(); }
 }
Ленивая синхронизация


• Добавляем в Node поле boolean marked.
• Удаление в 2 фазы:
   - node.marked = true; // Логическое удаление
   - Физическое удаление из списка
• Инвариант: Все непомеченные (неудаленные) элементы
  всегда в списке
• Результат:
   - Для валидации не надо просматривать список (только проверить
     что элементы не удалены логически и pred.next == curr). В
     остальном, код добавление идентичен оптимистичному.
   - Поиск элемента в списке можно делать без ожидания (wait-free)
Ленивая синхронизация: удаление

 retry: while(true) {
     Node pred = head, curr = pred.next;
     while (curr.key < key) {
         pred = curr; curr = curr.next;
     }
     pred.lock(); curr.lock();
     try {
         if (!validate(pred, curr)) continue retry;
         if (curr.key == key) {
             curr.marked = true;     точка линеаризации
             pred.next = curr.next;
             return true;
         } else return false;
     } finally { curr.unlock(); pred.unlock(); }
 }
Ленивая синхронизация: валидация

 boolean validate(Node pred, Node curr) {
     return !pred.marked &&
            !curr.marked &&
            pred.next == curr;
 }
Ленивая синхронизация: поиск (wait-free!)

 boolean contains(int key) {
     Node curr = head;
     while (curr.key < key) {
         curr = curr.next;
     }
     return key == curr.key && !curr.marked;
 }

                            точка линеаризации
                             успешного поиска
Неблокирующая синхронизация


• Простое использование Compare-And-Set (CAS) не помогает –
  удаления двух соседних элементов будут конфликтовать.
• Объединим next и marked в одну переменную {next,marked},
  которую будем атомарно менять используя CAS
   - Каждая операция модификации будет выполнятся одним
     успешным CAS-ом.
   - Успешное выполнение CAS-а является точкой линеаризации.
• При выполнении операции удаления или добавления будем
  пытаться произвести физическое удаление
   - Добавление и удаление будут работать без блокировки (lock-free)
   - Поиск элемента будет работать без ожидания (wait-free)
Неблокирующая синхронизация: добавление

  retry: while (true) {
       Node pred, curr; {pred,curr} = find(key);
       if (curr.key == key) return false; else {
            Node = new Node(key, item);
            node.{next,marked} = {curr,false};
линеаризация   if (CAS(pred.{next,marked}, {curr,false},
                                           {next,false})
                   return true;
       }
  }
Неблокирующая синхронизация: поиск окна

 {Node,Node} find(int key) {
  retry: while(true) {
      Node pred = head, curr = pred.next, succ;
      while (true) {
          {succ,boolean cmk} = curr.{next,marked};
          if (cmk) { // Если curr логически удален
              if (!CAS(pred.{next,marked},
                      {curr,false}, {succ,false}))
                  continue retry;
              curr = succ;
          } else {
              if (curr.key >= key) return {pred,curr};
              pred = curr; curr = succ;
          }
      }
  }
Неблокирующая синхронизация: удаление

 retry: while (true) {
      Node pred, curr; {pred,curr} = find(key);
      if (curr.key != key) return false; else {
           Node succ = curr.next;
линеаризация  if (!CAS(curr.{next,marked}, {next,false},
                                             {next,true})
                  continue retry;
           // оптимизация – попытаемся физ. удалить
           CAS(pred.{next,marked}, {curr,false}
                                    {succ,false});
           return true;
      }
 }
Универсальное построение без блокировок с
использованием CAS

• Вся структура данных представляется как указатель на
  объект, содержимое которого никогда не меняется.
• Любые операции чтения работают без ожидания.
• Любые операции модификации создают полную копию
  структуры, меняют её, из пытаются подменить указать на неё с
  помощью одного Compare-And-Set (CAS).
   - В случае ошибки CAS – повтор.
• Частный случай этого подхода: вся структура данных влезает
  в одно машинное слово, например счетчик.
Атомарный счетчик

 int counter;

 int getAndIncrement(int increment) {
     retry: while(true) {
         int old = counter;
         int updated = old + increment;
         if (CAS(counter, old, updated))
             return old;
     }
 }
Работа с древовидными структурами без
блокировок

• Структура представлена в виде дерева
• Тогда операции изменения можно реализовать в виде одного
  CAS, заменяющего указатель на root дерева.
   - Неизменившуюся часть дерева можно использовать в новой
     версии дерева, т.е. не нужно копировать всю структуру данных.
• Частный случай этого подхода: LIFO стек
 class Node {
     T item;
     Node next;
 }
 // Пустой стек это указатель на null
 Node top = null;
Операции с LIFO стеком

 void push(T item) {
     retry: while(true) {
         Node node = new Node(item, top);
         if (CAS(top, node.next, node))     линеаризация
             return;
     }
 }
 T pop() {
     retry: while(true) {
         Node node = top;
         if (node == null) throw new EmptyStack();
         if (CAS(top, node, node.next))    линеаризация
             return node.item;
     }
 }
FIFO очередь без блокировок (lock-free)


• Так же односвязный список, но два указателя: head и tail.
• Алгоритм придумали Michael & Scott в 1996 году.
 class Node {
     T item;
     Node next;
 }

 // Пустой список состоит их одного элемента-заглушки
 Node head = new Node(null);
 Node tail = head;
Добавление в очередь

 void enqueue(T item) {
      Node node = new Node(item);
      retry: while(true) {
           Node last = tail, next = last.next;
           if (next == null) {
линеаризация   if (!CAS(last.next, null, node))
                   continue retry;
               // оптимизация – сами переставляем tail
               CAS(tail, last, node);
               return;
           }
           // Помогаем другим операциям enqueue с tail
           CAS(tail, last, next);
      }
 }
Удаление из очереди

 T dequeue() {
      retry: while(true) {
           Node first = head, last = tail,
                next = first.next;
           if (first == last) {
               if (next == null) throw new EmptyQueue();
               // Помогаем операциям enqueue с tail
               CAS(tail, last, next);
           } else {
линеаризация   if (CAS(head, first, next))
                    return next.item;
           }
      }
 }
Работа без GC, проблема ABA


• Память освобождается явно через “free” с добавлением в
  список свободной памяти:
   - Содержимое ячейки может меняться произвольным образом,
     пока на неё удерживается указатель
      • решение – дополнительные перепроверки
   - CAS может ошибочно отработать из-за проблемы ABA
      • решение – добавление версии к указателю
• Альтернативное решение – свой GC
Очереди/стеки на массивах


• Структуры на массивах быстрей работают на практике из-за
  локальности доступа к данным
• Очевидные решения не работают
   - Стек на массиве не работает
   - Очередь работает только при проходе по памяти один раз (можно
     развернуть очередь со списками для увеличения
     быстродействия)
• Неочевидные решения
   - Дек без помех (Obstruction-free Deque)
   - DCAS/CASn (Обновление нескольких слов одновременно)
   - Используя дескрипторы операций (универсальная конструкция)
Дек без помех


• Каждый элемента массива должен содержать элемент и
  версию, которые мы будем атомарно обновлять CAS-ом
• Пустые элементы будут заполнены правыми и левыми нулями
  (RN и LN)
• Указатели на правый и левый край будут храниться
  «приблизительно» и подбираться перед выполнением
  операций с помощью оракула (rightOracle и leftOracle)
  // массив на MAX элементов (0..MAX-1)
  {T item, int ver} a[MAX];
  int left, right; // прибл. указатель на LN и RN
Оракул для поиска правого края

 // Должен находить такое место что:
 //    a[k] == RN && a[k – 1] != RN
 // Должен корректно работать «без помех»

 int rightOracle() {
     int k = right; // только для оптимизации
     while (a[k] != RN) k++;
     while (a[k-1] == RN) k--;
     right = k; // запомнили для оптимизации
     return k;
 }
Добавление справа

 void rightPush(T item) {
  retry: while(true) {
      int k = rightOracle();
      {T item,int ver} prev = a[k-1], cur = a[k];
      if (prev.item == RN || cur.item != RN) continue;
      if (k == MAX-1) throw new FullDeque();
      if (CAS(a[k-1], prev, {prev.item,prev.ver+1} &&
          CAS(a[k], cur, {item,cur.ver+1})
          return; // успешно закончили
 }
Удаление справа

 T rightPop() {
  retry: while(true) {
      int k = oracleRight();
      {T item,int ver} cur = a[k-1], next = a[k];
      if (cur.item == RN || next.item != RN) continue;
      if (cur.item == LN) throw new EmptyDeque();
      if (CAS(a[k], next, {RN,next.ver+1} &&
          CAS(a[k-1], cur, {RN,cur.ver+1})
          return cur.item; // успешно закончили
 }
Хэш-таблицы


• Два основных способа разрешения коллизий
   - Прямая адресация: каждая ячейка хранит список элементов
      • Естественный параллелизм, легко делать раздельные
        блокировки/нарезку блокировок (lock striping)
      • Применяя алгоритмы работы со списками/множествами можно
        сделать реализацию без блокировок
   - Открытая адресация: ищем в других ячейках
      • На практике быстрей искать в соседних элементах, но требует
        хэш-функции хорошего качества
      • Так же возможна реализация без блокировок (занимаем
        ячейку через CAS), но требует специальной техники удаления
• Изменение размера хэш-таблицы (rehash)

Más contenido relacionado

La actualidad más candente

ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...Alexey Paznikov
 
Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6Dima Dzuba
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...Alexey Paznikov
 
1 встреча — Параллельное программирование (А. Свириденков)
1 встреча — Параллельное программирование (А. Свириденков)1 встреча — Параллельное программирование (А. Свириденков)
1 встреча — Параллельное программирование (А. Свириденков)Smolensk Computer Science Club
 
Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)Dmitry Tsitelov
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...Alexey Paznikov
 
Введение в Clojure (Никита Прокопов)
Введение в Clojure (Никита Прокопов)Введение в Clojure (Никита Прокопов)
Введение в Clojure (Никита Прокопов)mainstreamless
 
Модель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, ЯндексМодель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, ЯндексYandex
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...Alexey Paznikov
 
Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x IntroductionFedor Vompe
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Sergey Platonov
 
020
020020
020JIuc
 
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMSergey Platonov
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
Multiprocessor Programming Intro (lecture 3)
Multiprocessor Programming Intro (lecture 3)Multiprocessor Programming Intro (lecture 3)
Multiprocessor Programming Intro (lecture 3)Dmitry Tsitelov
 
Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)Roman Elizarov
 
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Sigma Software
 
Probabilistic Verification in Computational Systems Design
Probabilistic Verification in Computational Systems DesignProbabilistic Verification in Computational Systems Design
Probabilistic Verification in Computational Systems DesignIosif Itkin
 

La actualidad más candente (20)

ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++.   Р...
ПВТ - осень 2014 - Лекция 5 - Многопоточное программирование в языке С++. Р...
 
Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6Объектно-ориентированное программирование. Лекция 5 и 6
Объектно-ориентированное программирование. Лекция 5 и 6
 
Zagursky
ZagurskyZagursky
Zagursky
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
1 встреча — Параллельное программирование (А. Свириденков)
1 встреча — Параллельное программирование (А. Свириденков)1 встреча — Параллельное программирование (А. Свириденков)
1 встреча — Параллельное программирование (А. Свириденков)
 
Generics
GenericsGenerics
Generics
 
Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)Multiprocessor Programming Intro (lecture 2)
Multiprocessor Programming Intro (lecture 2)
 
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
ПВТ - весна 2015 - Лекция 7. Модель памяти С++. Внеочередное выполнение инстр...
 
Введение в Clojure (Никита Прокопов)
Введение в Clojure (Никита Прокопов)Введение в Clojure (Никита Прокопов)
Введение в Clojure (Никита Прокопов)
 
Модель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, ЯндексМодель памяти C++ - Андрей Янковский, Яндекс
Модель памяти C++ - Андрей Янковский, Яндекс
 
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
ПВТ - осень 2014 - Лекция 4 - Стандарт POSIX Threads. Реентерабельность. Сигн...
 
Cpp0x Introduction
Cpp0x IntroductionCpp0x Introduction
Cpp0x Introduction
 
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++ Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
Юрий Ефимочев, Компилируемые в реальном времени DSL для С++
 
020
020020
020
 
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVMДмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
Дмитрий Кашицын, Троллейбус из буханки: алиасинг и векторизация в LLVM
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
Multiprocessor Programming Intro (lecture 3)
Multiprocessor Programming Intro (lecture 3)Multiprocessor Programming Intro (lecture 3)
Multiprocessor Programming Intro (lecture 3)
 
Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)Многопоточные Алгоритмы (для BitByte 2014)
Многопоточные Алгоритмы (для BitByte 2014)
 
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
Опыт применения активных объектов во встраиваемых системах. Архитектурные асп...
 
Probabilistic Verification in Computational Systems Design
Probabilistic Verification in Computational Systems DesignProbabilistic Verification in Computational Systems Design
Probabilistic Verification in Computational Systems Design
 

Destacado

Digital matters event information
Digital matters event informationDigital matters event information
Digital matters event informationBranded Ltd
 
Universidad Autonoma De Guerrero
Universidad Autonoma De GuerreroUniversidad Autonoma De Guerrero
Universidad Autonoma De Guerreroociel parra
 
Athletic Business 2013 - San Diego - Technology's Approaching Impact on the ...
Athletic Business 2013 - San Diego -  Technology's Approaching Impact on the ...Athletic Business 2013 - San Diego -  Technology's Approaching Impact on the ...
Athletic Business 2013 - San Diego - Technology's Approaching Impact on the ...Ted Vickey
 
Day after day...
Day after day...Day after day...
Day after day...Vili 48
 
Concorso 65 Coadiutori Banca d'Italia - Bando
Concorso 65 Coadiutori Banca d'Italia - BandoConcorso 65 Coadiutori Banca d'Italia - Bando
Concorso 65 Coadiutori Banca d'Italia - BandoConcorsando.it
 
American rap presentation
American rap presentationAmerican rap presentation
American rap presentationmireiaxorto
 
El Mundo En 100 Personas
El Mundo En 100 PersonasEl Mundo En 100 Personas
El Mundo En 100 PersonasFree- Dominius
 
Namasmaran Bestseller On Superliving Dr. Shriniwas Kashalikar
Namasmaran Bestseller On Superliving  Dr. Shriniwas KashalikarNamasmaran Bestseller On Superliving  Dr. Shriniwas Kashalikar
Namasmaran Bestseller On Superliving Dr. Shriniwas Kashalikarshivsr5
 
Embracing the New Social Media
Embracing the New Social MediaEmbracing the New Social Media
Embracing the New Social MediaRedPrairie
 
Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)
Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)
Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)Dr.-Ing. Thomas Hartmann
 
20100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture0820100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture08Computer Science Club
 
Kennedy Power PointChapter 49
Kennedy Power PointChapter 49Kennedy Power PointChapter 49
Kennedy Power PointChapter 49Rachel King
 

Destacado (20)

Digital matters event information
Digital matters event informationDigital matters event information
Digital matters event information
 
bedrijfspresentatie
bedrijfspresentatiebedrijfspresentatie
bedrijfspresentatie
 
Universidad Autonoma De Guerrero
Universidad Autonoma De GuerreroUniversidad Autonoma De Guerrero
Universidad Autonoma De Guerrero
 
Athletic Business 2013 - San Diego - Technology's Approaching Impact on the ...
Athletic Business 2013 - San Diego -  Technology's Approaching Impact on the ...Athletic Business 2013 - San Diego -  Technology's Approaching Impact on the ...
Athletic Business 2013 - San Diego - Technology's Approaching Impact on the ...
 
Day after day...
Day after day...Day after day...
Day after day...
 
Concorso 65 Coadiutori Banca d'Italia - Bando
Concorso 65 Coadiutori Banca d'Italia - BandoConcorso 65 Coadiutori Banca d'Italia - Bando
Concorso 65 Coadiutori Banca d'Italia - Bando
 
American rap presentation
American rap presentationAmerican rap presentation
American rap presentation
 
Rogaine
RogaineRogaine
Rogaine
 
El Mundo En 100 Personas
El Mundo En 100 PersonasEl Mundo En 100 Personas
El Mundo En 100 Personas
 
2013.05 - LDOW 2013 @ WWW 2013
2013.05 - LDOW 2013 @ WWW 20132013.05 - LDOW 2013 @ WWW 2013
2013.05 - LDOW 2013 @ WWW 2013
 
La placa madre sesión 05
La placa madre sesión 05La placa madre sesión 05
La placa madre sesión 05
 
Namasmaran Bestseller On Superliving Dr. Shriniwas Kashalikar
Namasmaran Bestseller On Superliving  Dr. Shriniwas KashalikarNamasmaran Bestseller On Superliving  Dr. Shriniwas Kashalikar
Namasmaran Bestseller On Superliving Dr. Shriniwas Kashalikar
 
Embracing the New Social Media
Embracing the New Social MediaEmbracing the New Social Media
Embracing the New Social Media
 
Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)
Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)
Doctoral Examination at the Karlsruhe Institute of Technology (08.07.2016)
 
20100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture0820100321 virtualization igotti_lecture08
20100321 virtualization igotti_lecture08
 
Que Nos Paso
Que Nos PasoQue Nos Paso
Que Nos Paso
 
1. cover ppl
1. cover ppl1. cover ppl
1. cover ppl
 
Mcdi u1 ea_lula
Mcdi u1 ea_lulaMcdi u1 ea_lula
Mcdi u1 ea_lula
 
Kennedy Power PointChapter 49
Kennedy Power PointChapter 49Kennedy Power PointChapter 49
Kennedy Power PointChapter 49
 
Glenthorne Media Academy
Glenthorne Media AcademyGlenthorne Media Academy
Glenthorne Media Academy
 

Similar a 20090222 parallel programming_lecture01-07

C++ осень 2012 лекция 5
C++ осень 2012 лекция 5C++ осень 2012 лекция 5
C++ осень 2012 лекция 5Technopark
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Yandex
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksMikhail Kurnosov
 
javascript
javascriptjavascript
javascriptsovest
 
javascript_part1
javascript_part1javascript_part1
javascript_part1sovest
 
Базовые операторы Java
Базовые операторы JavaБазовые операторы Java
Базовые операторы Javametaform
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Platonov Sergey
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey TeplyakovAlex Tumanoff
 
9. java lecture library
9. java lecture library9. java lecture library
9. java lecture libraryMERA_school
 
Atomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAtomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAlexey Fyodorov
 
Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)
Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)
Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)Ontico
 
язык програмирования
язык програмированияязык програмирования
язык програмированияOlegmingalev1997
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksMikhail Kurnosov
 
Погружение в Dart
Погружение в DartПогружение в Dart
Погружение в DartSergey Penkovsky
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?Yandex
 
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4
Объектно-Ориентированное Программирование на C++, Лекции  3 и 4 Объектно-Ориентированное Программирование на C++, Лекции  3 и 4
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4 Dima Dzuba
 

Similar a 20090222 parallel programming_lecture01-07 (20)

C++ осень 2012 лекция 5
C++ осень 2012 лекция 5C++ осень 2012 лекция 5
C++ осень 2012 лекция 5
 
Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11Дмитрий Прокопцев — R-ссылки в С++11
Дмитрий Прокопцев — R-ссылки в С++11
 
Лекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building BlocksЛекция 8. Intel Threading Building Blocks
Лекция 8. Intel Threading Building Blocks
 
верификация
верификацияверификация
верификация
 
javascript
javascriptjavascript
javascript
 
javascript_part1
javascript_part1javascript_part1
javascript_part1
 
Базовые операторы Java
Базовые операторы JavaБазовые операторы Java
Базовые операторы Java
 
Step cpp0201
Step cpp0201Step cpp0201
Step cpp0201
 
Thread
ThreadThread
Thread
 
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
Павел Сушин «Асинхронное программирование на С++: callbacks, futures, fibers»
 
Deep Dive C# by Sergey Teplyakov
Deep Dive  C# by Sergey TeplyakovDeep Dive  C# by Sergey Teplyakov
Deep Dive C# by Sergey Teplyakov
 
9. java lecture library
9. java lecture library9. java lecture library
9. java lecture library
 
Atomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithmsAtomics, CAS and Nonblocking algorithms
Atomics, CAS and Nonblocking algorithms
 
Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)
Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)
Хранимые процедуры в NoSQL СУБД на примере Tarantool / Денис Линник (Mail.Ru)
 
язык програмирования
язык програмированияязык програмирования
язык програмирования
 
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building BlocksЛекция 8: Многопоточное программирование: Intel Threading Building Blocks
Лекция 8: Многопоточное программирование: Intel Threading Building Blocks
 
Погружение в Dart
Погружение в DartПогружение в Dart
Погружение в Dart
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
Антон Потапов — С++ контейнеры и многопоточность: вместе или врозь?
 
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4
Объектно-Ориентированное Программирование на C++, Лекции  3 и 4 Объектно-Ориентированное Программирование на C++, Лекции  3 и 4
Объектно-Ориентированное Программирование на C++, Лекции 3 и 4
 

Más de Computer Science Club

20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugsComputer Science Club
 
20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugs20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugsComputer Science Club
 
20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugsComputer Science Club
 
20140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture1220140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture12Computer Science Club
 
20140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture1120140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture11Computer Science Club
 
20140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture1020140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture10Computer Science Club
 
20140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture0920140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture09Computer Science Club
 
20140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture0220140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture02Computer Science Club
 
20140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture0120140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture01Computer Science Club
 
20140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-0420140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-04Computer Science Club
 
20140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture0120140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture01Computer Science Club
 

Más de Computer Science Club (20)

20141223 kuznetsov distributed
20141223 kuznetsov distributed20141223 kuznetsov distributed
20141223 kuznetsov distributed
 
Computer Vision
Computer VisionComputer Vision
Computer Vision
 
20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs
 
20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugs20140531 serebryany lecture02_find_scary_cpp_bugs
20140531 serebryany lecture02_find_scary_cpp_bugs
 
20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs20140531 serebryany lecture01_fantastic_cpp_bugs
20140531 serebryany lecture01_fantastic_cpp_bugs
 
20140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture1220140511 parallel programming_kalishenko_lecture12
20140511 parallel programming_kalishenko_lecture12
 
20140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture1120140427 parallel programming_zlobin_lecture11
20140427 parallel programming_zlobin_lecture11
 
20140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture1020140420 parallel programming_kalishenko_lecture10
20140420 parallel programming_kalishenko_lecture10
 
20140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture0920140413 parallel programming_kalishenko_lecture09
20140413 parallel programming_kalishenko_lecture09
 
20140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture0220140329 graph drawing_dainiak_lecture02
20140329 graph drawing_dainiak_lecture02
 
20140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture0120140329 graph drawing_dainiak_lecture01
20140329 graph drawing_dainiak_lecture01
 
20140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-0420140310 parallel programming_kalishenko_lecture03-04
20140310 parallel programming_kalishenko_lecture03-04
 
20140223-SuffixTrees-lecture01-03
20140223-SuffixTrees-lecture01-0320140223-SuffixTrees-lecture01-03
20140223-SuffixTrees-lecture01-03
 
20140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture0120140216 parallel programming_kalishenko_lecture01
20140216 parallel programming_kalishenko_lecture01
 
20131106 h10 lecture6_matiyasevich
20131106 h10 lecture6_matiyasevich20131106 h10 lecture6_matiyasevich
20131106 h10 lecture6_matiyasevich
 
20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich
 
20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich20131027 h10 lecture5_matiyasevich
20131027 h10 lecture5_matiyasevich
 
20131013 h10 lecture4_matiyasevich
20131013 h10 lecture4_matiyasevich20131013 h10 lecture4_matiyasevich
20131013 h10 lecture4_matiyasevich
 
20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich
 
20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich20131006 h10 lecture3_matiyasevich
20131006 h10 lecture3_matiyasevich
 

20090222 parallel programming_lecture01-07

  • 1. Параллельное программирование Роман Елизаров, 2009 elizarov@devexperts.com
  • 2. Взаимное исключение • Взаимное исключение (Mutual Exclusion) • Отсутствие блокировки (Freedom from Deadlock) • Отсутствие голодания (Freedom from Starvation) run() { int i = getCurrentThreadID(); while (true) { nonCriticalSection(); lock(i); criticalSection(); unlock(i); } }
  • 3. Взаимное исключение, попытка 1 boolean want[2]; lock(int i) { want[i] = true; while (want[1 – i]); // wait } unlock(int i) { want[i] = false; }
  • 4. Взаимное исключение, попытка 2 int victim; lock(int i) { victim = i; while (victim == i); // wait } unlock(int i) { }
  • 5. Взаимное исключение, алгоритм Петерсона boolean want[2]; int victim; lock(int i) { want[i] = true; victim = i; while (want[1 – i] && victim == i); // wait } unlock(int i) { want[i] = false; }
  • 6. Взаимное исключение, алгоритм Петерсона для N потоков int level[N]; int victim[N]; lock(int i) { for (int j = 1; j < N; j++) { level[i] = j; victim[j] = i; while exists k != i : level[k] >= j && victim[j] == i; // wait } unlock(int i) { level[i] = 0; }
  • 7. Честность • Отсутствие голодания • Линейное ожидание, квадратичное ожидание и т.п. • Первым пришел, первым обслужен (FCFS – First Come First Served) lock() { DoorwaySection(); // wait-free code WaitingSection(); }
  • 8. Взаимное исключение, алгоритм Лампорта (алгоритм булочника – вариант 1) boolean want[N]; // init with false Label label[N]; // init with 0 lock(int i) { want[i] = true; label[i] = max(label[0], …, label[N-1]) + 1; while exists k != i : want[k] && (label[k], k) < (label[i], i); } unlock(int i) { want[i] = false; }
  • 9. Взаимное исключение, алгоритм Лампорта (алгоритм булочника – вариант 2) boolean choosing[N]; // init with false Label label[N]; // init with inf lock(int i) { choosing[i] = true; label[i] = max(label[0], …, label[N-1]) + 1; choosing[i] = false; while exists k != i : choosing[k] || (label[k], k) < (label[i], i); } unlock(int i) { label[i] = inf; }
  • 10. Разделяемые объекты • Корректность реализации объекта - Тихая согласованность (Quiescent consistency) - Последовательная согласованность (Sequential consistency) - Линеаризуемость (Linearizability) • Прогресс - Без помех (Obstruction-free) - Без блокировок (Lock-free) - Без ожидания (Wait-free)
  • 11. Регистры • Разделяемые регистры – базовый объект для общения потоков между собой interface Register<T> { T read(); void write(T val); }
  • 12. Классификация регистров • Безопасные (safe), регулярные (regular), атомарные (atomic) • Один читатель, много читателей (SR, MR) • Один писатель, много писателей (SW, MW) • Булевские значение, множественные значения • Самый примитивный регистр – Safe SRSW Boolean register • Самый сложный регистр – Atomic MRMW M-Valued register
  • 13. Построение регистров • Будем строить более сложные регистры из более простых без ожиданий (wait-free образом). - Safe SRSW Boolean register - Regular SRSW Boolean register - Regular SRSW M-Valued register - Atomic SRSW M-Valued register - Atomic MRSW M-Valued register - Atomic MRMW M-Valued register
  • 14. Атомарный снимок состояния N регистров • Набор SW атомарных регистров (по регистру на поток) • Любой поток может вызвать scan() чтобы получить снимок состояния всех регистров • Методы должны быть атомарными (линеаризуемыми) interface Snapshot<T> { void update(int i, T val); T[] scan(); }
  • 15. Атомарный снимок состояния N регистров, без блокировок (lock free) // каждый регистр хранит версию “version” (T val, Label version) register[N]; void update(int i, T val) { // wait-free register[i] = (val, register[i].version+1); } T[] scan() { // obstruction-free (T, Label)[] old = copyOf(register); // with loop while (true) { (T, Label)[] cur = copyOf(register); if (equal(old, cur)) return cur.val; else old = cur; } }
  • 16. Атомарный снимок состояния N регистров, без ожидания (wait-free) – update // каждый регистр так же хранит копию снимка “snap” (T val, Label version, T[] snap) register[N]; void update(int i, T val) { // wait-free T[] snap = scan(); register[i] = (val, register[i].version+1, snap); }
  • 17. Атомарный снимок состояния N регистров, без ожидания (wait-free) – scan T[] scan() { // wait-free, O(N^2) time (T, Label, T[])[] old = copyOf(register); boolean updated[N]; loop: while (true) { (T, Label, T[])[] cur = copyOf(register); for (int j = 0; j < N; j++) if (cur[j].version != old[j].version) if (updated[j]) return cur[j].snap; else { updated[j] = true; old = cur; continue loop; } return cur.val; } }
  • 18. Консенсус • Согласованность (consistent): все потоки должны вернуть одно и то же значение из метода decide • Обоснованность (valid): возвращенное значение было входным значением какого-то из потоков interface Consensus<T> { T decide(T val); }
  • 19. Консенсусное число • Если с помощью класса объектов C можно реализовать консенсусный протокол без ожидания (wait-free) для N потоков (и не больше), то говорят что у класса C консенсусное число равно N. • ТЕОРЕМА: Атомарные регистры имеют консенсусное число 1. - Т.е. с помощью атомарных регистров даже 2 потока не могут придти к консенсусу без ожидания (докажем от противного) для для 2-х возможных значений при T = {0, 1} - С ожиданием задача решается очевидно (с помощью любого алгоритма взаимного исключения).
  • 20. Определения и леммы для любых классов объектов • Определения и концепции: - Рассматриваем дерево состояния, листья – конечные состояния помеченные 0 или 1 (в зависимости от значения консенсуса). - x-валентное состояние системы (x = 0,1) – консенсус во всех нижестоящих листьях будет x. - Бивалентное состояние – возможен консенсус как 0 так и 1. - Критическое состояние – такое бивалентное состояние, все дети которого одновалентны. • ЛЕММА: Существует начальное бивалентное состояние. • ЛЕММА: Существует критическое состояние.
  • 21. Доказательство для атомарных регистров • Рассмотрим возможные пары операций в критическом состоянии: - Операции над разными регистрами – коммутируют. - Два чтения – коммутируют. - любая операция + Запись – состояние пишущего потока не зависит от порядка операций.
  • 22. Read-Modify-Write регистры • Для функции или класса функций F(args): T -> T - getAndSet (exchange), getAndIncrement, getAndAdd и т.п. - get (read) это тоже [тривиальная] RMW операция для F == id. сlass RMWRegister<T> { private T val; T getAndF(args…) atomic { T old = val; val = F(T, args); return old; } }
  • 23. Нетривиальные RMW регистры • Консенсусное число нетривиального RMW регистра >= 2. - Нужно чтобы была хотя бы одна «подвижная» точка функции F, например F(v0) = v1 != v0. T proposed[2]; RMWRegister rmw; // начальное значение v0 T decide(T val) { int i = myThreadId(); // i = 0,1 – номер потока proposed[i] = val; if (rmw.getAndF() == v0) return proposed[i]; else return proposed[1 – i]; }
  • 24. Common2 RMW регистры • Определения - F1 и F2 коммутируют если F1(F2(x)) == F2(F1(x)) - F1 перезаписывает F2 если F1(F2(x)) == F1(x) - Класс С RMW регистров принадлежит Common2, если любая пара функций либо коммутирует, либо одна из функций перезаписывает другую. • ТЕОРЕМА: Нетривиальный класс Common2 RMW регистров имеет консенсусное число 2. - Третий поток не может отличить глобальное состоянием при изменения порядка выполнения коммутирующих или перезаписывающих операций в критическом состоянии.
  • 25. Универсальные объекты • Объект с консенсусный числом бесконечность называется универсальным объектом. - По определению, с помощью него можно реализовать консенсусный протокол для любого числа потоков. • Пример: compareAndSet aka testAndSet (возвращает boolean), compareAndExchange (возвращает старое значение – RMW) private T x; boolean compareAndSet(T val, T expected) atomic { if (x == expected) { x = val; return true; } else return false; }
  • 26. compareAndSet (CAS) и консенсус // реализация консенсусного протокола через CAS+GET T decide(T val) { if (compareAndSet(val, INITIAL)) return val; else return get(); } // реализация консенсусного протокола через CMPXCHG T decide(T val) { T old = compareAndExchange(val, INITIAL); if (old == INITIAL) return val; else return old; }
  • 27. Универсальность консенсуса • ТЕОРЕМА: Любой последовательный объект можно реализовать без ожидания (wait-free) для N потоков используя консенсусный протокол для N объектов. - Следствие1: С помощью любого класса объектов с консенсусным числом N можно реализовать любой объект с консенсусным числом <= N. - Следствие2: С помощью универсального объекта можно реализовать любой объект.
  • 28. Иерархия объектов Консенсусное Объект число 1 Атомарные регистры, снимок состояния нескольких регистров 2 getAndSet (атомарный обмен), getAndAdd, очередь, стэк m Атомарная запись m регистров из m(m+1)/2 регистров ∞ compareAndSet, LoadLinked/StoreConditional
  • 29. Многопоточные (Thread-Safe) объекты (алгоритмы и структуры данных) на практике • Многопоточный объект включает в себя синхронизацию потоков (блокирующую или не блокирующую), которая позволяет его использовать из нескольких потоков одновременно без дополнительной внешней синхронизации - Специфицируется через последовательное поведение - По умолчанию требуется линеаризуемость операций (более слабые формы согласованности – редко) - Редко удается реализовать все операции без ожидания (wait- free). Часто приходится идти на компромиссные решения. • ВНИМАНИЕ: Пока пишем псевдокод. Доведение его до реального кода будем обсуждать отдельно.
  • 30. Разные подходы к синхронизации потоков при работе с общей структурой данных • Типы синхронизации: - Грубая (Coarse-grained) синхронизация - Тонкая (Fine-grained) синхронизация - Оптимистичная (Optimistic) синхронизация - Ленивая (Lazy) синхронизация - Неблокирующая (Nonblocking) синхронизация • Проще всего для списочных структур данных (с них и начнем), хотя на практике массивы работают существенно быстрей
  • 31. Пример: Множество на основе односвязного списка • ИНВАРИАНТ: node.key < node.next.key class Node { int key; T item; Node next; } // Пустой список состоит их 2-х граничных элементов Node head = new Node(Integer.MIN_VALUE, null); head.next = new Node(Integer.MAX_VALUE, null);
  • 32. Грубая синхронизация • Обеспечиваем взаимное исключение всех операций через общий Mutex lock.
  • 33. Грубая синхронизация: поиск boolean contains(int key) { lock.lock(); try { Node curr = head; while (curr.key < key) { curr = curr.next; } return key == curr.key; } finally { lock.unlock(); } }
  • 34. Грубая синхронизация: добавление boolean add(int key, T item) { lock.lock(); try { Node pred = head, curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } if (key == curr.key) return false; else { Node = new Node(key, item); node.next = curr; pred.next = node; return true; } } finally { lock.unlock(); } }
  • 35. Грубая синхронизация: удаление boolean remove(int key, T item) { lock.lock(); try { Node pred = head, curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } if (key == curr.key) { pred.next = curr.next; return true; else { return false; } } finally { lock.unlock(); } }
  • 36. Тонкая синхронизация • Обеспечиваем синхронизацию через взаимное исключение на каждом элементе. • При любых операциях одновременно удерживаем блокировку текущего и предыдущего элемента (чтобы не утерять инвариант pred.next == curr).
  • 37. Тонкая синхронизация: добавление Node pred = head; pred.lock(); Node curr = pred.next; curr.lock(); try { while (curr.key < key) { pred.unlock(); pred = curr; curr = curr.next; curr.lock(); } if (key == curr.key) return false; else { Node = new Node(key, item); node.next = curr; pred.next = node; return true; } } finally { curr.unlock(); pred.unlock(); }
  • 38. Оптимистичная синхронизация • Ищем элемент без синхронизации (оптимистично предполагая что никто не помешает), но перепроверяем с синхронизацией - Если перепроверка обломалась, то начинаем операцию заново • Имеет смысл только если обход структуры дешев и быстр, а обход с синхронизацией медленный и дорогой
  • 39. Оптимистичная синхронизация: поиск retry: while(true) { Node pred = head, curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); curr.lock(); try { if (!validate(pred, curr)) continue retry; return curr.key == key; } finally { curr.unlock(); pred.unlock(); } }
  • 40. Оптимистичная синхронизация: валидация boolean validate(Node pred, Node curr) { Node node = head; while (node.key <= pred.key) { if (node == pred) return pred.next == curr; node = node.next; } return false; }
  • 41. Оптимистичная синхронизация: добавление retry: while(true) { Node pred = head, curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); curr.lock(); try { if (!validate(pred, curr)) continue retry; if (curr.key == key) return false; else { Node = new Node(key, item); node.next = curr; pred.next = node; return true; } } finally { curr.unlock(); pred.unlock(); } }
  • 42. Оптимистичная синхронизация: удаление retry: while(true) { Node pred = head, curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); curr.lock(); try { if (!validate(pred, curr)) continue retry; if (curr.key == key) { pred.next = curr.next; return true; } else return false; } finally { curr.unlock(); pred.unlock(); } }
  • 43. Ленивая синхронизация • Добавляем в Node поле boolean marked. • Удаление в 2 фазы: - node.marked = true; // Логическое удаление - Физическое удаление из списка • Инвариант: Все непомеченные (неудаленные) элементы всегда в списке • Результат: - Для валидации не надо просматривать список (только проверить что элементы не удалены логически и pred.next == curr). В остальном, код добавление идентичен оптимистичному. - Поиск элемента в списке можно делать без ожидания (wait-free)
  • 44. Ленивая синхронизация: удаление retry: while(true) { Node pred = head, curr = pred.next; while (curr.key < key) { pred = curr; curr = curr.next; } pred.lock(); curr.lock(); try { if (!validate(pred, curr)) continue retry; if (curr.key == key) { curr.marked = true; точка линеаризации pred.next = curr.next; return true; } else return false; } finally { curr.unlock(); pred.unlock(); } }
  • 45. Ленивая синхронизация: валидация boolean validate(Node pred, Node curr) { return !pred.marked && !curr.marked && pred.next == curr; }
  • 46. Ленивая синхронизация: поиск (wait-free!) boolean contains(int key) { Node curr = head; while (curr.key < key) { curr = curr.next; } return key == curr.key && !curr.marked; } точка линеаризации успешного поиска
  • 47. Неблокирующая синхронизация • Простое использование Compare-And-Set (CAS) не помогает – удаления двух соседних элементов будут конфликтовать. • Объединим next и marked в одну переменную {next,marked}, которую будем атомарно менять используя CAS - Каждая операция модификации будет выполнятся одним успешным CAS-ом. - Успешное выполнение CAS-а является точкой линеаризации. • При выполнении операции удаления или добавления будем пытаться произвести физическое удаление - Добавление и удаление будут работать без блокировки (lock-free) - Поиск элемента будет работать без ожидания (wait-free)
  • 48. Неблокирующая синхронизация: добавление retry: while (true) { Node pred, curr; {pred,curr} = find(key); if (curr.key == key) return false; else { Node = new Node(key, item); node.{next,marked} = {curr,false}; линеаризация if (CAS(pred.{next,marked}, {curr,false}, {next,false}) return true; } }
  • 49. Неблокирующая синхронизация: поиск окна {Node,Node} find(int key) { retry: while(true) { Node pred = head, curr = pred.next, succ; while (true) { {succ,boolean cmk} = curr.{next,marked}; if (cmk) { // Если curr логически удален if (!CAS(pred.{next,marked}, {curr,false}, {succ,false})) continue retry; curr = succ; } else { if (curr.key >= key) return {pred,curr}; pred = curr; curr = succ; } } }
  • 50. Неблокирующая синхронизация: удаление retry: while (true) { Node pred, curr; {pred,curr} = find(key); if (curr.key != key) return false; else { Node succ = curr.next; линеаризация if (!CAS(curr.{next,marked}, {next,false}, {next,true}) continue retry; // оптимизация – попытаемся физ. удалить CAS(pred.{next,marked}, {curr,false} {succ,false}); return true; } }
  • 51. Универсальное построение без блокировок с использованием CAS • Вся структура данных представляется как указатель на объект, содержимое которого никогда не меняется. • Любые операции чтения работают без ожидания. • Любые операции модификации создают полную копию структуры, меняют её, из пытаются подменить указать на неё с помощью одного Compare-And-Set (CAS). - В случае ошибки CAS – повтор. • Частный случай этого подхода: вся структура данных влезает в одно машинное слово, например счетчик.
  • 52. Атомарный счетчик int counter; int getAndIncrement(int increment) { retry: while(true) { int old = counter; int updated = old + increment; if (CAS(counter, old, updated)) return old; } }
  • 53. Работа с древовидными структурами без блокировок • Структура представлена в виде дерева • Тогда операции изменения можно реализовать в виде одного CAS, заменяющего указатель на root дерева. - Неизменившуюся часть дерева можно использовать в новой версии дерева, т.е. не нужно копировать всю структуру данных. • Частный случай этого подхода: LIFO стек class Node { T item; Node next; } // Пустой стек это указатель на null Node top = null;
  • 54. Операции с LIFO стеком void push(T item) { retry: while(true) { Node node = new Node(item, top); if (CAS(top, node.next, node)) линеаризация return; } } T pop() { retry: while(true) { Node node = top; if (node == null) throw new EmptyStack(); if (CAS(top, node, node.next)) линеаризация return node.item; } }
  • 55. FIFO очередь без блокировок (lock-free) • Так же односвязный список, но два указателя: head и tail. • Алгоритм придумали Michael & Scott в 1996 году. class Node { T item; Node next; } // Пустой список состоит их одного элемента-заглушки Node head = new Node(null); Node tail = head;
  • 56. Добавление в очередь void enqueue(T item) { Node node = new Node(item); retry: while(true) { Node last = tail, next = last.next; if (next == null) { линеаризация if (!CAS(last.next, null, node)) continue retry; // оптимизация – сами переставляем tail CAS(tail, last, node); return; } // Помогаем другим операциям enqueue с tail CAS(tail, last, next); } }
  • 57. Удаление из очереди T dequeue() { retry: while(true) { Node first = head, last = tail, next = first.next; if (first == last) { if (next == null) throw new EmptyQueue(); // Помогаем операциям enqueue с tail CAS(tail, last, next); } else { линеаризация if (CAS(head, first, next)) return next.item; } } }
  • 58. Работа без GC, проблема ABA • Память освобождается явно через “free” с добавлением в список свободной памяти: - Содержимое ячейки может меняться произвольным образом, пока на неё удерживается указатель • решение – дополнительные перепроверки - CAS может ошибочно отработать из-за проблемы ABA • решение – добавление версии к указателю • Альтернативное решение – свой GC
  • 59. Очереди/стеки на массивах • Структуры на массивах быстрей работают на практике из-за локальности доступа к данным • Очевидные решения не работают - Стек на массиве не работает - Очередь работает только при проходе по памяти один раз (можно развернуть очередь со списками для увеличения быстродействия) • Неочевидные решения - Дек без помех (Obstruction-free Deque) - DCAS/CASn (Обновление нескольких слов одновременно) - Используя дескрипторы операций (универсальная конструкция)
  • 60. Дек без помех • Каждый элемента массива должен содержать элемент и версию, которые мы будем атомарно обновлять CAS-ом • Пустые элементы будут заполнены правыми и левыми нулями (RN и LN) • Указатели на правый и левый край будут храниться «приблизительно» и подбираться перед выполнением операций с помощью оракула (rightOracle и leftOracle) // массив на MAX элементов (0..MAX-1) {T item, int ver} a[MAX]; int left, right; // прибл. указатель на LN и RN
  • 61. Оракул для поиска правого края // Должен находить такое место что: // a[k] == RN && a[k – 1] != RN // Должен корректно работать «без помех» int rightOracle() { int k = right; // только для оптимизации while (a[k] != RN) k++; while (a[k-1] == RN) k--; right = k; // запомнили для оптимизации return k; }
  • 62. Добавление справа void rightPush(T item) { retry: while(true) { int k = rightOracle(); {T item,int ver} prev = a[k-1], cur = a[k]; if (prev.item == RN || cur.item != RN) continue; if (k == MAX-1) throw new FullDeque(); if (CAS(a[k-1], prev, {prev.item,prev.ver+1} && CAS(a[k], cur, {item,cur.ver+1}) return; // успешно закончили }
  • 63. Удаление справа T rightPop() { retry: while(true) { int k = oracleRight(); {T item,int ver} cur = a[k-1], next = a[k]; if (cur.item == RN || next.item != RN) continue; if (cur.item == LN) throw new EmptyDeque(); if (CAS(a[k], next, {RN,next.ver+1} && CAS(a[k-1], cur, {RN,cur.ver+1}) return cur.item; // успешно закончили }
  • 64. Хэш-таблицы • Два основных способа разрешения коллизий - Прямая адресация: каждая ячейка хранит список элементов • Естественный параллелизм, легко делать раздельные блокировки/нарезку блокировок (lock striping) • Применяя алгоритмы работы со списками/множествами можно сделать реализацию без блокировок - Открытая адресация: ищем в других ячейках • На практике быстрей искать в соседних элементах, но требует хэш-функции хорошего качества • Так же возможна реализация без блокировок (занимаем ячейку через CAS), но требует специальной техники удаления • Изменение размера хэш-таблицы (rehash)