Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

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

О.В.Сухорослов "Многопотчное программирование. Часть 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

×