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

8,864 views
8,762 views

Published on

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

Published in: Technology, News & Politics
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
8,864
On SlideShare
0
From Embeds
0
Number of Embeds
1,361
Actions
Shares
0
Downloads
222
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

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

  1. 1. 02 Многопоточное программирование О.В. Сухорослов oleg.sukhoroslov@gmail.com 24.02.2011О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 1 / 61
  2. 2. Синхронизация Безопасный доступ к общим данным Взаимное исключение и memory barrier (см. лекцию 1) О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 2 / 61
  3. 3. Синхронизация Безопасный доступ к общим данным Взаимное исключение и memory barrier (см. лекцию 1) Координация действий между потоками Условная синхронизация О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 2 / 61
  4. 4. Поиск шаблона в тексте lecture2.textsearch.SeqTextSearch 1 public class SeqTextSearch { 2 ... 3 4 public static void main ( String [] args ) { 5 long start = System . c u r r e n t T i m e M i l l i s (); 6 try { 7 String filePath = args [0]; 8 String pattern = args [1]; 910 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 . p ri nt S ta ck T ra ce ();18 }19 long end = System . c u r r e n t T i m e M i l l i s ();20 System . out . println ( " Total time : " + ( end - start ) + " ms " );21 }22 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 3 / 61
  5. 5. Запуск XML-файл, 370 Mb Pattern: ‘[w-.]+@([w-]+.){1,2}[a-zA-Z]{2,4}‘ Read time: 8333 ms Search time: 44016 ms Found 98 matches Total time: 52352 ms О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 4 / 61
  6. 6. OutOfMemoryErrorException in thread " main " java . lang . OutOfMemoryError : Java heap space at 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 -Xmx256m java -Xms2g -Xmx2g Eclipse: Run / Arguments / VM arguments О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 5 / 61
  7. 7. ParallelTextSearch1 О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 6 / 61
  8. 8. SearchTask lecture2.textsearch.ParallelTextSearch1.SearchTask 1 static class SearchTask implements Runnable { 2 3 private List < String > text ; 4 private int from , to ; 5 private Pattern regex ; 6 public List < String > results ; 7 8 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
  9. 9. ParallelTextSearch1 (main) lecture2.textsearch.ParallelTextSearch1 1 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
  10. 10. Запуск ParallelTextSearch1 Read time: 8437 ms Read time: 8333 ms Search time: 26034 ms Search time: 44016 ms Found 98 matches Found 98 matches Total time: 34472 ms Total time: 52352 ms О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 9 / 61
  11. 11. ParallelTextSearch2 О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 10 / 61
  12. 12. Producer-Consumer О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 11 / 61
  13. 13. BaseBoundedBuffer lecture2.textsearch.BaseBoundedBuffer 1 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 Base BoundedBuffer ( int capacity ) { 9 this . buf = ( T []) new Object [ capacity ];10 }1112 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
  14. 14. BaseBoundedBuffer (2) lecture2.textsearch.BaseBoundedBuffer 1 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 } 910 public synchronized final boolean isFull () {11 return count == buf . length ;12 }1314 public synchronized final boolean isEmpty () {15 return count == 0;16 }1718 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 13 / 61
  15. 15. PollingQueue lecture2.textsearch.PollingQueue 1 public class PollingQueue <T > extends BaseBoundedBuffer <T > { 2 ... 3 public void put ( T v ) throws I n t e r r u p t e d E x c e p t i o n { 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 I n t e r r u p t e d E x c e p t i o n {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
  16. 16. WaitNotifyQueue lecture2.textsearch.WaitNotifyQueue 1 public class WaitNotifyQueue <T > extends BaseBoundedBuffer <T > { 2 3 public W a it No t if yQ u eu e ( int size ) { 4 super ( size ); 5 } 6 7 public synchronized void put ( T v ) throws I n t e r r u p t e d E x c e p t i o n { 8 while ( isFull ()) 9 wait ();10 doPut ( v );11 notifyAll ();12 }1314 public synchronized T take () throws I n t e r r u p t e d E x c e p t i o n {15 while ( isEmpty ())16 wait ();17 T v = doTake ();18 notifyAll ();19 return v ;20 }2122 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 15 / 61
  17. 17. 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
  18. 18. ConditionQueue lecture2.textsearch.ConditionQueue 1 public class ConditionQueue <T > { 2 3 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 ; 8 9 protected Conditio nQueue ( int capacity ) {10 this . buf = ( T []) new Object [ capacity ];11 }1213 public void put ( T x ) throws I n t e r r u p t e d E x c e p t i o n {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
  19. 19. ConditionQueue (2) lecture2.textsearch.ConditionQueue 1 public T take () throws I n t e r r u p t e d E x c e p t i o n { 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
  20. 20. Reader.run() lecture2.textsearch.ParallelTextSearch2.Reader.run() 1 try { 2 input = new Buff eredRe ader ( 3 new I n p u t S t r e a m R e a d e r ( new Fi le I np u tS tr e am ( 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 . p ri nt S ta ck T ra ce ();12 } finally {13 queue . put ( null ); // poison pill14 ...15 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 19 / 61
  21. 21. Searcher.run() lecture2.textsearch.ParallelTextSearch2.Searcher.run() 1 Matcher matcher ; 2 TextLine line ; 3 4 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
  22. 22. ParallelTextSearch2 lecture2.textsearch.ParallelTextSearch2.main() 1 WaitNotifyQueue < TextLine > queue = 2 new WaitNotifyQueue < TextLine >(1000); 3 4 Reader reader = new Reader ( filePath , queue ); 5 reader . start (); 6 7 Searcher searcher = new Searcher ( queue , pattern ); 8 searcher . start (); 910 reader . join ();11 searcher . join (); О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 21 / 61
  23. 23. Запуск ParallelTextSearch2 Read time: 53228 ms Read time: 8333 ms Search time: 53246 ms Search time: 44016 ms Found 98 matches Found 98 matches Total time: 53251 ms Total time: 52352 ms О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 22 / 61
  24. 24. ParallelTextSearch3 lecture2.textsearch.ParallelTextSearch3.main() 1 WaitNotifyQueue <List<TextLine>> queue = 2 new WaitNotifyQueue <List<TextLine> >( QUEUE_SIZE ); 3 4 Reader reader = new Reader ( filePath , queue ); 5 reader . start (); 6 7 Searcher searcher = new Searcher ( queue , pattern ); 8 searcher . start (); 910 reader . join ();11 searcher . join (); О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 23 / 61
  25. 25. Запуск ParallelTextSearch3 QUEUE_SIZE = 1000 SPLIT_SIZE = 1000 Read time: 38131 ms Read time: 8333 ms Search time: 42837 ms Search time: 44016 ms Found 98 matches Found 98 matches Total time: 42841 ms Total time: 52352 ms О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 24 / 61
  26. 26. Готовые реализации очередей Интерфейс BlockingQueue Реализации LinkedBlockingQueue ArrayBlockingQueue PriorityBlockingQueue SynchronousQueue DelayQueue О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 25 / 61
  27. 27. ParallelTextSearch4 lecture2.textsearch.ParallelTextSearch4.main() 1 BlockingQueue < List < TextLine > > queue = 2 new ArrayBlockingQueue < List < TextLine > >( QUEUE_SIZE ); 3 4 Reader reader = new Reader ( filePath , queue ); 5 reader . start (); 6 7 Searcher searcher = new Searcher ( queue , pattern ); 8 searcher . start (); 910 reader . join ();11 searcher . join (); О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 26 / 61
  28. 28. Запуск ParallelTextSearch4 QUEUE_SIZE = 100 SPLIT_SIZE = 1000 Read time: 41502 ms Read time: 8333 ms Search time: 41989 ms Search time: 44016 ms Found 98 matches Found 98 matches Total time: 41992 ms Total time: 52352 ms О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 27 / 61
  29. 29. ParallelTextSearch5 Пул потоков, ведущих поиск в фрагментах текста О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 28 / 61
  30. 30. Executor1 Executor executor = ...;2 executor . execute ( new RunnableTask1 ());3 executor . execute ( new RunnableTask2 ());4 ... О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 29 / 61
  31. 31. Простые примеры1 class DirectExecutor implements Executor {2 public void execute ( Runnable r ) {3 r . run ();4 }5 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 30 / 61
  32. 32. Простые примеры1 class DirectExecutor implements Executor {2 public void execute ( Runnable r ) {3 r . run ();4 }5 }1 class Th r e a d P e r T a s k Execu tor implements Executor {2 public void execute ( Runnable r ) {3 new Thread ( r ). start ();4 }5 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 30 / 61
  33. 33. Интерфейсы ExecutorService, Callable и Future ExecutorService shutdown(), shutdownNow() Future<T> submit(Callable<T> task) О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 31 / 61
  34. 34. Интерфейсы ExecutorService, Callable и Future ExecutorService shutdown(), shutdownNow() Future<T> submit(Callable<T> task) Callable<T> T call() О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 31 / 61
  35. 35. Интерфейсы ExecutorService, Callable и Future ExecutorService shutdown(), 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
  36. 36. Пул потоков1 ThreadPoo lE xe cut or ( int corePoolSize ,2 int maximumPoolSize ,3 long keepAliveTime ,4 TimeUnit unit ,5 BlockingQueue < Runnable > workQueue ) О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 32 / 61
  37. 37. Фабрика Executors newCachedThreadPool() newFixedThreadPool(int nThreads) newSingleThreadExecutor() newScheduledThreadPool(int corePoolSize) ... О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 33 / 61
  38. 38. SearchTask lecture2.textsearch.ParallelTextSearch5.SearchTask 1 static class SearchTask implements Callable < List < String > > { 2 3 private List < TextLine > lines ; 4 private Pattern regex ; 5 6 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
  39. 39. ParallelTextSearch5 lecture2.textsearch.ParallelTextSearch5.main() 1 exec = Executors . n ew F i x e d T h r e a d P o o l ( 2 Runtime . getRuntime (). a v a i l a b l e P r o c e s s o r s ()); 3 4 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
  40. 40. Запуск ParallelTextSearch5 24 ядра SPLIT_SIZE = 100 24 processors Read time: 8333 ms Found 98 matches Search time: 44016 ms Total time: 8485 ms Found 98 matches Total time: 52352 ms О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 36 / 61
  41. 41. Как сделать поиск еще быстрее? О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 37 / 61
  42. 42. Циклический барьер О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 38 / 61
  43. 43. java.util.concurrent.CyclicBarrier CyclicBarrier(int parties) CyclicBarrier(int parties, Runnable barrierAction) О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 39 / 61
  44. 44. java.util.concurrent.CyclicBarrier CyclicBarrier(int parties) CyclicBarrier(int parties, Runnable barrierAction) barrier.await() : arrival index (N-1,...,0) InterruptedException BrokenBarrierException О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 39 / 61
  45. 45. java.util.concurrent.CyclicBarrier CyclicBarrier(int parties) CyclicBarrier(int parties, Runnable barrierAction) barrier.await() : arrival index (N-1,...,0) InterruptedException BrokenBarrierException getNumberWaiting() reset() ... О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 39 / 61
  46. 46. Алгоритм Флойда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
  47. 47. FloydCycBarrier lecture2.floyd.FloydCycBarrier 1 public static void main ( String [] args ) { 2 int [][] A = Graph Genera tor . generate (1000); 3 E xe cu t or Se r vi c e exec = 4 Executors . n e w F i x e d T h r e a d P o o l ( numThreads ); 5 try { 6 CyclicBarrier b = new CyclicBarrier ( numThreads + 1); 7 8 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 . p ri nt S ta ck T ra ce ();18 } finally {19 exec . shutdown ();20 }21 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 41 / 61
  48. 48. FloydTask lecture2.floyd.FloydCycBarrier.FloydTask 1 static class FloydTask implements Runnable { 2 ... 3 4 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 ( I n t e r r u p t e d E x c e p t i o n e ) {17 } catch ( B r o k e n B a r r i e r E x c e p t i o n e ) {18 e . p ri nt S ta ck T ra ce ();19 }20 }21 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 42 / 61
  49. 49. Число итераций не известно? (вариант 1) 1 // wait for all threads to finish iteration 2 int myNum = b . await (); 3 4 // last thread checks stop condition 5 if ( myNum == 0) { 6 // check condition , set done flag ... 7 } 8 9 // sync after condition check10 b . await (); О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 43 / 61
  50. 50. Число итераций не известно? (вариант 2)1 barrier = new CyclicBarrier (N ,2 new Runnable () {3 public void run () {4 // check condition , set done flag5 }6 );Действие выполняется при достижении барьера всеми потоками,перед тем как разблокировать их О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 44 / 61
  51. 51. Домашнее задание (ДЗ №1, Задача 2) Напишите многопоточный поисковый робот, реализующий обход Web-графа в ширину и сохраняющий на диск все посещенные страницы При запуске роботу передаются URL начальной страницы и глубина обхода Робот не должен посещать одну и ту же страницу более одного раза Попытайтесь добиться максимальной скорости работы робота, обоснуйте используемый для этого подход Заготовка для робота: lecture2.crawler.CrawlerUtils (см. код к лекции) О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 45 / 61
  52. 52. Дополнительный материал Maurice Herlihy, Nir Shavit. The Art of Multiprocessor Programming. Morgan Kaufmann, 2008 О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 46 / 61
  53. 53. Lock1 public interface Lock {2 public void lock (); // before entering critical section3 public void unlock (); // before leaving critical section4 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 47 / 61
  54. 54. LockOne 1 class LockOne implements Lock { 2 private volatile boolean [] flag = new boolean [2]; // ERROR 3 // thread - local index , 0 or 1 4 5 public void lock () { 6 int i = ThreadID . get (); 7 int j = 1 - i ; 8 flag [ i ] = true ; 9 while ( flag [ j ]) {} // wait10 }1112 public void unlock () {13 int i = ThreadID . get ();14 flag [ i ] = false ;15 }16 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 48 / 61
  55. 55. LockTwo 1 class LockTwo implements Lock { 2 private volatile int victim ; 3 4 public void lock () { 5 int i = ThreadID . get (); 6 victim = i ; // let the other go first 7 while ( victim == i ) {} // wait 8 } 910 public void unlock () {}11 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 49 / 61
  56. 56. PetersonLock 1 class Peterson implements Lock { 2 // thread - local index , 0 or 1 3 private volatile boolean [] flag = new boolean [2]; // ERROR 4 private volatile int victim ; 5 6 public void lock () { 7 int i = ThreadID . get (); 8 int j = 1 - i ; 9 flag [ i ] = true ; // I ’m interested10 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
  57. 57. Filter Lock 1 class Filter implements Lock { 2 A t o m ic I nt e ge r Ar r ay level ; // volatile int [] level ; 3 A t o m ic I nt e ge r Ar r ay victim ; // volatile int [] victim ; 4 5 public Filter ( int n ) { 6 level = new int [ n ]; 7 victim = new int [ n ]; // use 1.. n -1 8 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
  58. 58. Lamport’s Bakery Algorithm 1 class Bakery implements Lock { 2 volatile boolean [] flag ; // ERROR 3 volatile Label [] label ; // ERROR 4 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
  59. 59. Важная теорема Любой алгоритм, решающий задачу взаимного исключения для N потоков (с гарантией от deadlock) путем чтения и записи памяти, должен использовать как минимум N адресов памяти О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 53 / 61
  60. 60. Как быть? О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 54 / 61
  61. 61. Test-And-Set-Lock 1 public class TASLock implements Lock { 2 AtomicBoolean state = new AtomicBoolean ( false ); 3 4 public void lock () { 5 while ( state . getAndSet ( true )) {} 6 } 7 8 public void unlock () { 9 state . set ( false );10 }11 } О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 55 / 61
  62. 62. Test-Test-And-Set-Lock 1 public class TTASLock implements Lock { 2 AtomicBoolean state = new AtomicBoolean ( false ); 3 4 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
  63. 63. 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
  64. 64. Backoff 1 public class Backoff { 2 final int minDelay , maxDelay ; 3 int limit ; 4 final Random random ; 5 6 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 I n t e r r u p t e d E x c e p t i o n {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
  65. 65. 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
  66. 66. 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 lock 8 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
  67. 67. Более сложные варианты О.В. Сухорослов 02 Многопоточное программирование () 24.02.2011 61 / 61

×