О.В.Сухорослов "Многопотчное программирование....

67
02 Многопоточное программирование О.В. Сухорослов [email protected] 24.02.2011 О.В. Сухорослов 02 Многопоточное программирование 24.02.2011 1 / 61

Upload: yandex

Post on 23-Dec-2014

5.455 views

Category:

Technology


3 download

DESCRIPTION

О.В.Сухорослов "Многопотчное программирование. Часть 2", 24.02.2012, место показа МФТИ, Школа анализа данных (ШАД)

TRANSCRIPT

02 Многопоточное программирование

О.В. Сухорослов

[email protected]

24.02.2011

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 1 / 61

Синхронизация

Безопасный доступ к общим даннымВзаимное исключение и memory barrier (см. лекцию 1)

Координация действий между потокамиУсловная синхронизация

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 2 / 61

Синхронизация

Безопасный доступ к общим даннымВзаимное исключение и memory barrier (см. лекцию 1)

Координация действий между потокамиУсловная синхронизация

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 2 / 61

Поиск шаблона в тексте

lecture2.textsearch.SeqTextSearch1 public class SeqTextSearch {2 ...34 public static void main(String [] args) {5 long start = System.currentTimeMillis ();6 try {7 String filePath = args [0];8 String pattern = args [1];9

10 List <String > text = readFile(filePath );11 List <String > results = search(text , pattern );1213 System.out.println(14 "Found " + results.size() + " matches:");15 ...16 } catch (Exception e) {17 e.printStackTrace ();18 }19 long end = System.currentTimeMillis ();20 System.out.println("Total time: " + (end - start) + " ms");21 }22 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 3 / 61

Запуск

XML-файл, 370 MbPattern: ‘[\w-\.]+@([\w-]+\.){1,2}[a-zA-Z]{2,4}‘

Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 4 / 61

OutOfMemoryError

Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java :2760)at java.util.Arrays.copyOf(Arrays.java :2734)at java.util.ArrayList.ensureCapacity(ArrayList.java :167)at java.util.ArrayList.add(ArrayList.java :351)at lecture2.textsearch.SeqTextSearch.readFile(SeqTextSearch.java :22)at lecture2.textsearch.SeqTextSearch.main(SeqTextSearch.java :54)

java -Xms<initial heap size> -Xmx<maximum heap size>java -Xms256m -Xmx256mjava -Xms2g -Xmx2gEclipse: Run / Arguments / VM arguments

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 5 / 61

ParallelTextSearch1

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 6 / 61

SearchTask

lecture2.textsearch.ParallelTextSearch1.SearchTask1 static class SearchTask implements Runnable {23 private List <String > text;4 private int from , to;5 private Pattern regex;6 public List <String > results;78 public SearchTask(List <String > text , int from , int to ,9 Pattern regex) {

10 ...11 }1213 public void run() {14 Matcher matcher;15 for (int i = from; i <= to; i++) {16 matcher = regex.matcher(text.get(i));17 while (matcher.find ()) {18 results.add (...);19 }20 }21 }22 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 7 / 61

ParallelTextSearch1 (main)

lecture2.textsearch.ParallelTextSearch11 public static void main(String [] args) {2 ...3 List <String > text = SeqTextSearch.readFile(filePath );4 ...5 SearchTask task1 = new SearchTask(6 text , 0, text.size() / 2 - 1, regex);7 SearchTask task2 = new SearchTask(8 text , text.size() / 2, text.size() - 1, regex);9 Thread thread1 = new Thread(task1);

10 Thread thread2 = new Thread(task2);11 thread1.start ();12 thread2.start ();1314 thread1.join();15 thread2.join();1617 ...18 task1.results.addAll(task2.results );19 System.out.println(20 "Found " + task1.results.size() + " matches");21 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 8 / 61

Запуск ParallelTextSearch1

Read time: 8437 msSearch time: 26034 msFound 98 matchesTotal time: 34472 ms

Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 9 / 61

ParallelTextSearch2

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 10 / 61

Producer-Consumer

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 11 / 61

BaseBoundedBuffer

lecture2.textsearch.BaseBoundedBuffer1 public abstract class BaseBoundedBuffer <T> {2

3 private final T[] buf;4 private int tail;5 private int head;6 private int count;7

8 protected BaseBoundedBuffer(int capacity) {9 this.buf = (T[]) new Object[capacity ];

10 }11

12 protected synchronized final void doPut(T v) {13 buf[tail] = v;14 if (++ tail == buf.length)15 tail = 0;16 ++count;17 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 12 / 61

BaseBoundedBuffer (2)

lecture2.textsearch.BaseBoundedBuffer1 protected synchronized final T doTake () {2 T v = buf[head];3 buf[head] = null;4 if (++ head == buf.length)5 head = 0;6 --count;7 return v;8 }9

10 public synchronized final boolean isFull () {11 return count == buf.length;12 }13

14 public synchronized final boolean isEmpty () {15 return count == 0;16 }17

18 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 13 / 61

PollingQueue

lecture2.textsearch.PollingQueue1 public class PollingQueue <T> extends BaseBoundedBuffer <T> {2 ...3 public void put(T v) throws InterruptedException {4 while (true) {5 synchronized (this) {6 if (! isFull ()) {7 doPut(v);8 return;9 }

10 }11 Thread.sleep(SLEEP_TIME );12 }13 }1415 public T take() throws InterruptedException {16 while (true) {17 synchronized (this) {18 if (! isEmpty ())19 return doTake ();20 }21 Thread.sleep(SLEEP_TIME );22 }23 }24 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 14 / 61

WaitNotifyQueue

lecture2.textsearch.WaitNotifyQueue1 public class WaitNotifyQueue <T> extends BaseBoundedBuffer <T> {23 public WaitNotifyQueue(int size) {4 super(size);5 }67 public synchronized void put(T v) throws InterruptedException {8 while (isFull ())9 wait ();

10 doPut(v);11 notifyAll ();12 }1314 public synchronized T take() throws InterruptedException {15 while (isEmpty ())16 wait ();17 T v = doTake ();18 notifyAll ();19 return v;20 }2122 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 15 / 61

java.util.concurrent.locks.Condition

Condition condition = lock.newCondition()

condition.await()await(long time, TimeUnit unit)awaitUntil(Date deadline)

condition.signal() / signallAll()

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 16 / 61

ConditionQueue

lecture2.textsearch.ConditionQueue1 public class ConditionQueue <T> {23 protected final Lock lock = new ReentrantLock ();4 private final Condition notFull = lock.newCondition ();5 private final Condition notEmpty = lock.newCondition ();6 private final T[] buf;7 private int tail , head , count;89 protected ConditionQueue(int capacity) {

10 this.buf = (T[]) new Object[capacity ];11 }1213 public void put(T x) throws InterruptedException {14 lock.lock ();15 try {16 while (count == buf.length)17 notFull.await ();18 buf[tail] = x;19 if (++ tail == buf.length)20 tail = 0;21 ++count;22 notEmpty.signal ();23 } finally {24 lock.unlock ();25 }26 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 17 / 61

ConditionQueue (2)

lecture2.textsearch.ConditionQueue1 public T take() throws InterruptedException {2 lock.lock ();3 try {4 while (count == 0)5 notEmpty.await ();6 T x = buf[head];7 buf[head] = null;8 if (++ head == buf.length)9 head = 0;

10 --count;11 notFull.signal ();12 return x;13 } finally {14 lock.unlock ();15 }16 }17 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 18 / 61

Reader.run()

lecture2.textsearch.ParallelTextSearch2.Reader.run()1 try {2 input = new BufferedReader(3 new InputStreamReader(new FileInputStream(filePath )));4 String line = null;5 int lineNum = 0;6 while ((line = input.readLine ()) != null) {7 queue.put(new TextLine(lineNum ,line ));8 lineNum ++;9 }

10 } catch (IOException e) {11 e.printStackTrace ();12 } finally {13 queue.put(null); // poison pill14 ...15 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 19 / 61

Searcher.run()

lecture2.textsearch.ParallelTextSearch2.Searcher.run()1 Matcher matcher;2 TextLine line;34 while (true) {5 line = queue.take ();6 if (line != null) {7 matcher = regex.matcher(line.getText ());8 while (matcher.find ()) {9 results.add (...);

10 }11 } else break;12 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 20 / 61

ParallelTextSearch2

lecture2.textsearch.ParallelTextSearch2.main()1 WaitNotifyQueue <TextLine > queue =2 new WaitNotifyQueue <TextLine >(1000);34 Reader reader = new Reader(filePath , queue );5 reader.start ();67 Searcher searcher = new Searcher(queue , pattern );8 searcher.start ();9

10 reader.join ();11 searcher.join ();

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 21 / 61

Запуск ParallelTextSearch2

Read time: 53228 msSearch time: 53246 msFound 98 matchesTotal time: 53251 ms

Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 22 / 61

ParallelTextSearch3

lecture2.textsearch.ParallelTextSearch3.main()1 WaitNotifyQueue <List<TextLine>> queue =2 new WaitNotifyQueue <List<TextLine>>(QUEUE_SIZE );34 Reader reader = new Reader(filePath , queue );5 reader.start ();67 Searcher searcher = new Searcher(queue , pattern );8 searcher.start ();9

10 reader.join ();11 searcher.join ();

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 23 / 61

Запуск ParallelTextSearch3

QUEUE_SIZE = 1000SPLIT_SIZE = 1000

Read time: 38131 msSearch time: 42837 msFound 98 matchesTotal time: 42841 ms

Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 24 / 61

Готовые реализации очередей

Интерфейс BlockingQueue

РеализацииLinkedBlockingQueueArrayBlockingQueuePriorityBlockingQueueSynchronousQueueDelayQueue

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 25 / 61

ParallelTextSearch4

lecture2.textsearch.ParallelTextSearch4.main()1 BlockingQueue <List <TextLine >> queue =2 new ArrayBlockingQueue <List <TextLine >>( QUEUE_SIZE );34 Reader reader = new Reader(filePath , queue );5 reader.start ();67 Searcher searcher = new Searcher(queue , pattern );8 searcher.start ();9

10 reader.join ();11 searcher.join ();

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 26 / 61

Запуск ParallelTextSearch4

QUEUE_SIZE = 100SPLIT_SIZE = 1000

Read time: 41502 msSearch time: 41989 msFound 98 matchesTotal time: 41992 ms

Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 27 / 61

ParallelTextSearch5

Пул потоков, ведущих поиск в фрагментах текста

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 28 / 61

Executor

1 Executor executor = ...;2 executor.execute(new RunnableTask1 ());3 executor.execute(new RunnableTask2 ());4 ...

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 29 / 61

Простые примеры

1 class DirectExecutor implements Executor {2 public void execute(Runnable r) {3 r.run();4 }5 }

1 class ThreadPerTaskExecutor implements Executor {2 public void execute(Runnable r) {3 new Thread(r).start ();4 }5 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 30 / 61

Простые примеры

1 class DirectExecutor implements Executor {2 public void execute(Runnable r) {3 r.run();4 }5 }

1 class ThreadPerTaskExecutor implements Executor {2 public void execute(Runnable r) {3 new Thread(r).start ();4 }5 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 30 / 61

Интерфейсы ExecutorService, Callable и Future

ExecutorServiceshutdown(), shutdownNow()Future<T> submit(Callable<T> task)

Callable<T>T call()

Future<T>boolean isDone()T get() / get(long timeout, TimeUnit unit)boolean cancel(boolean mayInterruptIfRunning)

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 31 / 61

Интерфейсы ExecutorService, Callable и Future

ExecutorServiceshutdown(), shutdownNow()Future<T> submit(Callable<T> task)

Callable<T>T call()

Future<T>boolean isDone()T get() / get(long timeout, TimeUnit unit)boolean cancel(boolean mayInterruptIfRunning)

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 31 / 61

Интерфейсы ExecutorService, Callable и Future

ExecutorServiceshutdown(), shutdownNow()Future<T> submit(Callable<T> task)

Callable<T>T call()

Future<T>boolean isDone()T get() / get(long timeout, TimeUnit unit)boolean cancel(boolean mayInterruptIfRunning)

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 31 / 61

Пул потоков

1 ThreadPoolExecutor(int corePoolSize ,2 int maximumPoolSize ,3 long keepAliveTime ,4 TimeUnit unit ,5 BlockingQueue <Runnable > workQueue)

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 32 / 61

Фабрика Executors

newCachedThreadPool()newFixedThreadPool(int nThreads)newSingleThreadExecutor()newScheduledThreadPool(int corePoolSize)...

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 33 / 61

SearchTask

lecture2.textsearch.ParallelTextSearch5.SearchTask1 static class SearchTask implements Callable <List <String >> {23 private List <TextLine > lines;4 private Pattern regex;56 public SearchTask(List <TextLine > split , Pattern regex) {7 this.lines = split;8 this.regex = regex;9 }

1011 public List <String > call() {12 List <String > results = new ArrayList <String >();13 for (TextLine line : lines) {14 Matcher matcher = regex.matcher(line.getText ());15 while (matcher.find ()) {16 results.add (...);17 }18 }19 return results;20 }21 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 34 / 61

ParallelTextSearch5

lecture2.textsearch.ParallelTextSearch5.main()1 exec = Executors.newFixedThreadPool(2 Runtime.getRuntime (). availableProcessors ());34 List <Future <List <String >>> results = new ...5 ...6 while ((line = input.readLine ()) != null) {7 split.add(new TextLine(lineNum , line ));8 if (split.size() == SPLIT_SIZE) {9 Future <List <String >> f =

10 exec.submit(new SearchTask(split , regex ));11 results.add(f);12 split = new ArrayList <TextLine >( SPLIT_SIZE );13 }14 lineNum ++;15 }1617 if (split.size() > 0) {18 Future <List <String >> f = exec.submit (...);19 results.add(f);20 }2122 int matchCount = 0;23 for (Future <List <String >> result : results) {24 matchCount += result.get(). size ();25 }2627 System.out.println("Found " + matchCount + " matches");

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 35 / 61

Запуск ParallelTextSearch5

24 ядраSPLIT_SIZE = 100

24 processorsFound 98 matchesTotal time: 8485 ms

Read time: 8333 msSearch time: 44016 msFound 98 matchesTotal time: 52352 ms

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 36 / 61

Как сделать поиск еще быстрее?

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 37 / 61

Циклический барьер

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 38 / 61

java.util.concurrent.CyclicBarrier

CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)

barrier.await() : arrival index (N-1,...,0)InterruptedExceptionBrokenBarrierException

getNumberWaiting()reset()...

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 39 / 61

java.util.concurrent.CyclicBarrier

CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)

barrier.await() : arrival index (N-1,...,0)InterruptedExceptionBrokenBarrierException

getNumberWaiting()reset()...

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 39 / 61

java.util.concurrent.CyclicBarrier

CyclicBarrier(int parties)CyclicBarrier(int parties, Runnable barrierAction)

barrier.await() : arrival index (N-1,...,0)InterruptedExceptionBrokenBarrierException

getNumberWaiting()reset()...

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 39 / 61

Алгоритм Флойда

1 for (k=0; k<N; k++) {2 for (i=0; i<N; i++) {3 for (j=0; j<N; j++) {4 A[i][j] = Math.min(A[i][j], A[i][k]+A[k][j]);5 }6 }7 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 40 / 61

FloydCycBarrier

lecture2.floyd.FloydCycBarrier1 public static void main(String [] args) {2 int [][] A = GraphGenerator.generate (1000);3 ExecutorService exec =4 Executors.newFixedThreadPool(numThreads );5 try {6 CyclicBarrier b = new CyclicBarrier(numThreads + 1);78 for (int i = 0; i < numThreads; i++) {9 exec.execute(new FloydTask(A, i, b));

10 }1112 for (int k = 0; k < A.length; k++) {13 b.await ();14 // System.out.println (" Iteration " + k);15 }16 } catch (Exception e) {17 e.printStackTrace ();18 } finally {19 exec.shutdown ();20 }21 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 41 / 61

FloydTask

lecture2.floyd.FloydCycBarrier.FloydTask1 static class FloydTask implements Runnable {2 ...34 public void run() {5 try {6 int i, j, k;7 for (k = 0; k < A.length; k++) {8 for (i = t; i < A.length; i += numThreads) {9 for (j = 0; j < A.length; j++) {

10 A[i][j] =11 Math.min(A[i][j], A[i][k] + A[k][j]);12 }13 }14 b.await ();15 }16 } catch (InterruptedException e) {17 } catch (BrokenBarrierException e) {18 e.printStackTrace ();19 }20 }21 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 42 / 61

Число итераций не известно? (вариант 1)

1 // wait for all threads to finish iteration2 int myNum = b.await ();3

4 // last thread checks stop condition5 if (myNum == 0) {6 // check condition , set done flag ...7 }8

9 // sync after condition check10 b.await ();

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 43 / 61

Число итераций не известно? (вариант 2)

1 barrier = new CyclicBarrier(N,2 new Runnable () {3 public void run() {4 // check condition , set done flag ...5 }6 );

Действие выполняется при достижении барьера всеми потоками,перед тем как разблокировать их

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 44 / 61

Домашнее задание (ДЗ №1, Задача 2)

Напишите многопоточный поисковый робот, реализующий обходWeb-графа в ширину и сохраняющий на диск все посещенныестраницы

При запуске роботу передаются URL начальной страницы иглубина обходаРобот не должен посещать одну и ту же страницу более одногораза

Попытайтесь добиться максимальной скорости работы робота,обоснуйте используемый для этого подход

Заготовка для робота: lecture2.crawler.CrawlerUtils (см. код клекции)

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 45 / 61

Дополнительный материал

Maurice Herlihy, Nir Shavit. The Art of Multiprocessor Programming.Morgan Kaufmann, 2008

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 46 / 61

Lock

1 public interface Lock {2 public void lock (); // before entering critical section3 public void unlock (); // before leaving critical section4 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 47 / 61

LockOne

1 class LockOne implements Lock {2 private volatile boolean [] flag = new boolean [2]; // ERROR3 // thread -local index , 0 or 145 public void lock() {6 int i = ThreadID.get();7 int j = 1 - i;8 flag[i] = true;9 while (flag[j]) {} // wait

10 }1112 public void unlock () {13 int i = ThreadID.get();14 flag[i] = false;15 }16 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 48 / 61

LockTwo

1 class LockTwo implements Lock {2 private volatile int victim;34 public void lock() {5 int i = ThreadID.get();6 victim = i; // let the other go first7 while (victim == i) {} // wait8 }9

10 public void unlock () {}11 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 49 / 61

PetersonLock

1 class Peterson implements Lock {2 // thread -local index , 0 or 13 private volatile boolean [] flag = new boolean [2]; // ERROR4 private volatile int victim;56 public void lock() {7 int i = ThreadID.get();8 int j = 1 - i;9 flag[i] = true; // I’m interested

10 victim = i; // you go first11 while (flag[j] && victim == i) {}; // wait12 }1314 public void unlock () {15 int i = ThreadID.get();16 flag[i] = false; // I’m not interested17 }18 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 50 / 61

Filter Lock

1 class Filter implements Lock {2 AtomicIntegerArray level; // volatile int[] level;3 AtomicIntegerArray victim; // volatile int[] victim;45 public Filter(int n) {6 level = new int[n];7 victim = new int[n]; // use 1..n-18 for (int i = 0; i < n; i++) {9 level[i] = 0;

10 }11 }12 public void lock() {13 int me = ThreadID.get ();14 for (int i = 1; i < n; i++) { // attempt level 115 level[me] = i;16 victim[i] = me;17 // spin while conflicts exist18 while (( EXISTS k != me) (level[k] >= i && victim[i] == me)) {};19 }20 }21 public void unlock () {22 int me = ThreadID.get ();23 level[me] = 0;24 }25 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 51 / 61

Lamport’s Bakery Algorithm

1 class Bakery implements Lock {2 volatile boolean [] flag; // ERROR3 volatile Label[] label; // ERROR4 public Bakery (int n) {5 flag = new boolean[n];6 label = new Label[n];7 for (int i = 0; i < n; i++) {8 flag[i] = false; label[i] = 0;9 }

10 }11 public void lock() {12 int i = ThreadID.get();13 flag[i] = true;14 label[i] = max(label[0], ..., label[n-1]) + 1;15 while (( EXISTS k != i)(flag[k] && (label[k],k) << (label[i],i))) {};16 }17 public void unlock () {18 flag[ThreadID.get()] = false;19 }20 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 52 / 61

Важная теорема

Любой алгоритм, решающий задачу взаимного исключения для Nпотоков (с гарантией от deadlock) путем чтения и записи памяти,должен использовать как минимум N адресов памяти

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 53 / 61

Как быть?

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 54 / 61

Test-And-Set-Lock

1 public class TASLock implements Lock {2 AtomicBoolean state = new AtomicBoolean(false );34 public void lock() {5 while (state.getAndSet(true)) {}6 }78 public void unlock () {9 state.set(false);

10 }11 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 55 / 61

Test-Test-And-Set-Lock

1 public class TTASLock implements Lock {2 AtomicBoolean state = new AtomicBoolean(false );34 public void lock() {5 while (true) {6 while (state.get()) {};7 if (!state.getAndSet(true))8 return;9 }

10 }1112 public void unlock () {13 state.set(false);14 }15 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 56 / 61

BackoffLock

1 public class BackoffLock implements Lock {2 private AtomicBoolean state = new AtomicBoolean(false );3 private static final int MIN_DELAY = ...;4 private static final int MAX_DELAY = ...;5 public void lock() {6 Backoff backoff = new Backoff(MIN_DELAY , MAX_DELAY );7 while (true) {8 while (state.get()) {};9 if (!state.getAndSet(true)) {

10 return;11 } else {12 backoff.backoff ();13 }14 }15 }16 public void unlock () {17 state.set(false);18 }19 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 57 / 61

Backoff

1 public class Backoff {2 final int minDelay , maxDelay;3 int limit;4 final Random random;56 public Backoff(int min , int max) {7 minDelay = min;8 maxDelay = min;9 limit = minDelay;

10 random = new Random ();11 }1213 public void backoff () throws InterruptedException {14 int delay = random.nextInt(limit);15 limit = Math.min(maxDelay , 2 * limit );16 Thread.sleep(delay);17 }18 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 58 / 61

MCSLock (1)

1 public class MCSLock implements Lock {2 AtomicReference <QNode > tail;3 ThreadLocal <QNode > myNode;4 public MCSLock () {5 queue = new AtomicReference <QNode >(null);6 myNode = new ThreadLocal <QNode >() {7 protected QNode initialValue () {8 return new QNode ();9 }

10 };11 }12 ...13 class QNode {14 boolean locked = false;15 QNode next = null;16 }17 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 59 / 61

MCSLock (2)

1 public void lock() {2 QNode qnode = myNode.get();3 QNode pred = tail.getAndSet(qnode );4 if (pred != null) {5 qnode.locked = true;6 pred.next = qnode;7 // wait until predecessor gives up the lock8 while (qnode.locked) {}9 }

10 }11 public void unlock () {12 QNode qnode = myNode.get();13 if (qnode.next == null) {14 if (tail.compareAndSet(qnode , null))15 return;16 // wait until predecessor fills in its next field17 while (qnode.next == null) {}18 }19 qnode.next.locked = false;20 qnode.next = null;21 }

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 60 / 61

Более сложные варианты

О.В. Сухорослов ()02 Многопоточное программирование 24.02.2011 61 / 61