Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Задачи синхронизации: классические и прикладные решения

Egor Tolstoy
September 28, 2015

Задачи синхронизации: классические и прикладные решения

Выступление на Rambler.iOS #4:
Видео: http://www.youtube.com/watch?v=y0UQEioIgTQ
Исходники: https://github.com/rambler-digital-solutions/synchronization-problems

Egor Tolstoy

September 28, 2015
Tweet

More Decks by Egor Tolstoy

Other Decks in Technology

Transcript

  1. Синхронизация • Состояние гонки - 
 работа приложения зависит от

    последовательности вызова секции его кода разными потоками.
  2. Синхронизация func incrementSharedVariable { // counter == 0 counter +=

    1 } Поток 1 Поток 2 Поток 3 counter ∈ [1,3]
  3. Синхронизация • Критическая секция - 
 участок кода, в котором

    одновременно может находиться только один поток.
  4. Синхронизация Алиса Боб а1: Съесть завтрак а2: Поработать а3: Съесть

    обед а4: Позвонить Бобу б1: Съесть завтрак б2: Дождаться звонка Алисы б3: Съесть обед а1 < a2 < a3 < a4 б1 < б2 < б3
  5. Синхронизация Алиса Боб а1: Съесть завтрак а2: Поработать а3: Съесть

    обед а4: Позвонить Бобу б1: Съесть завтрак б2: Дождаться звонка Алисы б3: Съесть обед а1 < a2 < a3 < a4 б1 < б2 < б3
  6. Синхронизация Алиса Боб а1: Съесть завтрак а2: Поработать а3: Съесть

    обед а4: Позвонить Бобу б1: Съесть завтрак б2: Дождаться звонка Алисы б3: Съесть обед а1 < a2 < a3 < a4 б1 < б2 < б3 б3 > б2 > a4 > a3
  7. Синхронизация • События считаются параллельными, если, изучив код программы, мы

    не можем утверждать, какое из них произойдет первым.
  8. Синхронизация • Семафор создается с начальным значением, • wait -

    уменьшает счетчик, • signal - увеличивает счетчик.
  9. Синхронизация class OperationScheduler { var readerQueue = NSOperationQueue() var writerQueue

    = NSOperationQueue() init () { // Читатели должны выполняться параллельно readerQueue.maxConcurrentOperationCount = MAX // Писатели должны выполняться последовательно writerQueue.maxConcurrentOperationCount = 1 } ... }
  10. Синхронизация func addReaderOperation(operation: NSBlockOperation) { // Зависим от выполнения всех

    писателей for writerOperation in writerQueue.operations { operation.addDependency(writerOperation) } readerQueue.addOperation(operation) }
  11. Синхронизация func addWriterOperation(operation: NSBlockOperation) { // Все читатели зависят от

    нового писателя for readerOperation in readerQueue.operations { readerOperation.addDependency(operation) } writerQueue.addOperation(operation) }
  12. Синхронизация func readersWriters() { let scheduler = OperationScheduler() scheduler.addWriter() for

    i in 1...5 { scheduler.addReader(i) } scheduler.addWriter() } > writer fired > writer fired > reader 2 fired > reader 3 fired > reader 1 fired > reader 5 fired > reader 4 fired
  13. Синхронизация • Не больше одного философа на вилку • Не

    допустить deadlock • Не допустить голод
  14. Синхронизация Ф.5 Ф.1 Ф.2 Ф.3 Ф.4 вилка 0 вилка 0

    вилка 0 вилка 0 вилка 0 deadlock :(
  15. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка вилка 0 вилка

    1 вилка 1 Ф.2 Семафор "официант" 2 Ф.1 1
  16. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 1 вилка 1 Ф.2 Семафор "официант" 2 Ф.1
  17. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 1 вилка 1 Ф.2 Семафор "официант" 1 Ф.1
  18. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 0 вилка 1 Ф.2 Семафор "официант" 1 Ф.1
  19. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 0 вилка 1 Ф.2 Семафор "официант" 0 Ф.1
  20. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 0 вилка 0 Ф.2 Семафор "официант" 0 Ф.1
  21. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 1

    вилка 0 вилка 0 Ф.2 Семафор "официант" 1 Ф.1
  22. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 0 вилка 0 Ф.2 Семафор "официант" 0 Ф.1
  23. Синхронизация Ф.5 Ф.3 Ф.4 вилка 1 вилка 0 вилка 0

    вилка 0 вилка 0 Ф.2 Семафор "официант" 1 Ф.1
  24. Синхронизация Ф.5 Ф.3 Ф.4 вилка 0 вилка 0 вилка 0

    вилка 0 вилка 0 Ф.2 Семафор "официант" 0 Ф.1
  25. Синхронизация class DiningPhilosophersOperationScheduler { var philosopherQueues = [NSOperationQueue]() init() {

    for _ in 0...4 { let philosopherQueue = NSOperationQueue() philosopherQueue.maxConcurrentOperationCount = 1 philosopherQueues.append(philosopherQueue) } } ... }
  26. Синхронизация class PhilosopherBlockOperation: NSBlockOperation { init(index: Int) { super.init() addExecutionBlock({

    print("philosopher \(index) is eating") sleep(2) print("philosopher \(index) puts forks") }) } }
  27. Синхронизация func startPhilosopher(index: Int) { let operation = PhilosopherBlockOperation(index: index)

    let leftQueue = getLeftPhilosopher(index) let leftPhilosopherEats = leftQueue.operationCount > 0 if (leftPhilosopherEats) { for leftOperation in leftQueue.operations { operation.addDependency(leftOperation) } } // То же и для правого соседа let currentPhilosopherQueue = philosopherQueues[index] currentPhilosopherQueue.addOperation(operation) }
  28. Синхронизация func diningPhilosophers() { let scheduler = DiningPhilosophersOperationScheduler() scheduler.startPhilosopher(0) scheduler.startPhilosopher(3)

    scheduler.startPhilosopher(2) scheduler.startPhilosopher(1) scheduler.startPhilosopher(4) } > philosopher 0 is thinking > philosopher 0 is eating > philosopher 3 is thinking > philosopher 3 is eating > philosopher 2 is thinking > philosopher 1 is thinking > philosopher 4 is thinking > philosopher 3 puts forks > philosopher 0 puts forks > philosopher 2 is eating > philosopher 4 is eating > philosopher 2 puts forks > philosopher 4 puts forks > philosopher 1 is eating > philosopher 1 puts forks
  29. Синхронизация > philosopher 0 is thinking > philosopher 0 is

    eating > philosopher 3 is thinking > philosopher 3 is eating > philosopher 2 is thinking > philosopher 1 is thinking > philosopher 4 is thinking > philosopher 3 puts forks > philosopher 0 puts forks > philosopher 2 is eating > philosopher 4 is eating > philosopher 2 puts forks > philosopher 4 puts forks > philosopher 1 is eating > philosopher 1 puts forks Ф.0 Ф.1 Ф.2 Ф.3 Ф.4
  30. Синхронизация func triggerHydrogenEvent(location: CGPoint) { let sprite = AtomNode.atom(AtomSprite.Hydrogen, location:

    location) self.addChild(sprite) self.scheduler.addHydrogen(sprite, block: atomBlock(sprite)) }
  31. Синхронизация class H2OOperationScheduler { let moleculeQueue = NSOperationQueue() // Этот

    блок вызывается при успешном сборе молекулы H2O var moleculeBlock: (Array<SKSpriteNode>) -> Void init(H2OBlock: (Array<SKSpriteNode>) -> Void) { moleculeQueue.maxConcurrentOperationCount = 1 moleculeBlock = H2OBlock } ... }
  32. Синхронизация func addHydrogen(node: SKSpriteNode, block: () -> Void) { let

    currentMolecule = obtainMolecule { (molecule) -> Bool in return molecule.hydrogen < 2 } let operation = AtomOperation(node: node, block: block) currentMolecule.addHydrogen(operation) }
  33. Синхронизация class H2OOperation: NSOperation { let atomQueue = NSOperationQueue() let

    moleculeBlock: (Array<SKSpriteNode>) -> Void var nodes = Array<SKSpriteNode>() ... override var ready: Bool { return hydrogen == 2 && oxygen == 1 } func addHydrogen(operation: AtomOperation) { nodes.append(operation.node) atomQueue.addOperation(operation) hydrogen++ } }
  34. Синхронизация class H2OOperation: NSOperation { ... override func main() {

    atomQueue.suspended = false atomQueue.waitUntilAllOperationsAreFinished() self.moleculeBlock(nodes) } ... }