2013-03-13 9 views
13

W docs Apple, to mówi:Jak utworzyć zakleszczenie w Grand Central Dispatch?

Ważne: Nigdy nie powinno wywołać dispatch_sync lub dispatch_sync_f funkcję z zadania, które jest wykonywany w tej samej kolejce, że jesteś planuje przekazać do funkcji. Jest to szczególnie ważne w przypadku kolejek szeregowych, które są zabezpieczone przed zakleszczeniem, ale powinny też być unikane w przypadku równoległych kolejek.

Jak napisać kod, aby zrobić dokładnie to?

+0

Chcesz przykład kodu, który tworzy impasu? – Vladimir

+0

Tak, proszę, do nauki – BlackMouse

+1

Zobacz także [to pytanie] (http://stackoverflow.com/questions/10330679/how-to-dispatch-on-main-queue-synchronously-without-a-adlock) dla realistycznego przykładu to może łatwo utknąć w martwym punkcie. – zoul

Odpowiedz

20

Celowo impas na pewnej kolejki:

dispatch_queue_t queue = dispatch_queue_create("my.label", DISPATCH_QUEUE_SERIAL); 
dispatch_async(queue, ^{ 
    dispatch_sync(queue, ^{ 
     // outer block is waiting for this inner block to complete, 
     // inner block won't start before outer block finishes 
     // => deadlock 
    }); 

    // this will never be reached 
}); 

To jasne tutaj, że zewnętrzne i wewnętrzne bloki działają na tej samej kolejce. Większość przypadków, w których do tego dojdzie, znajduje się w miejscach, w których mniej oczywiste jest, w którym kolejce dzwoni rozmówca z dispatch_sync. Zwykle występuje to w (głęboko) zagnieżdżonym stosie, w którym wykonywany jest kod w pewnej klasie, która została pierwotnie uruchomiona w określonej kolejce, i przez przypadek wywołujesz dispatch_sync do tej samej kolejki.

+0

Kiedy w martwym punkcie ... czy interfejs użytkownika nie powinien reagować? – BlackMouse

+2

@ user1251004 Tylko jeśli główna kolejka jest blokowana. –

+2

W tym przykładzie tylko utworzona 'kolejka' jest zablokowana. Główna kolejka szczęśliwie nadal działa. –

7

prosty kod, który tworzy impasu:

dispatch_queue_t q = dispatch_queue_create("deadlock queue", DISPATCH_QUEUE_SERIAL); 

NSLog(@"1"); 
dispatch_async(q, ^{ 
    NSLog(@"2"); 
    dispatch_sync(q, ^{ 
     NSLog(@"3"); 
    }); 
    NSLog(@"4"); 
}); 
NSLog(@"5"); 

wyjście Log:

1 
5 
2 

Tutaj wewnętrzny blok ma zostać uruchomiony na kolejce szeregowego q ale nie może uruchomić aż aktualny blok jest gotowy, natomiast obecny blok, z kolei, czeka wewnętrznie, aby zakończyć, jak nazywaliśmy to synchronicznie.

4

Najprostszym sposobem zablokowania jest dispatch_sync od aktualnego kolejki:

dispatch_sync(dispatch_get_current_queue(), ^{}); 

Blokuje gdy prąd kolejka jest kolejką seryjny, na przykład główny kolejek.

0

W najnowszej składni Swift:

let queue = DispatchQueue(label: "label") 
queue.async { 
    queue.sync { 
     // outer block is waiting for this inner block to complete, 
     // inner block won't start before outer block finishes 
     // => deadlock 
    } 
    // this will never be reached 
} 
Powiązane problemy