13

Następujące rzeczy są co wiem & zrozumieć:trzeba pewne wyjaśnienia dotyczące wysyłki kolejce, nici i NSRunLoop

Globalna kolejka jest współbieżne kolejka, która może wywoływać zadania do wielu wątków. Kolejność wykonywania zadania nie jest gwarantowana. np .:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), { 
for (int i; i<10; i++) { 
    doTask() 
} 
}) 

Jeśli chcę wysyłką do szeregowego kolejce, można użyć

dispatch_async(dispatch_queue_create("my.serial.queue", nil) { 
    ... 
} 

każdorazowo tylko jedno zadanie jest wysyłane do wątku & zostanie wykonany. Zamówienie jest FIFO.

===== Co Jestem zdezorientowany & nie w pełni zrozumieć =======

  1. Główny wątek ma NSRunLoop, zapętlenie zadań w głównym wątku. Zastanawiam się, jaka jest relacja między kolejką wysyłkową a pętlą uruchamiania? Czy mogę to zrozumieć, jeśli, wysyłając zadanie do głównego wątku, NSRunLoop głównego wątku otrzyma wysłane zadanie i je wykona?

  2. Co z globalną kolejką, która wysyła zadania do wielu wątków? Czy system iOS/OSX automatycznie tworzy nie tylko wątki, ale także tworzy NSRunLoop dla każdego wątku? a następnie uruchomić pętli w każdym wątku uzyskać wywołanie zadania z globalnej kolejki & go wykonać?

  3. Kto zna wątek? Czy funkcja dispatch_async() i dispatch_sync() wie, do którego wątku należy wywołać zadanie, czy czy wie, do którego wątku należy wysłać zadanie?

  4. Czy istnieje sposób programistycznego pobrania obiektu NSRunLoop z wątku (do którego jest wywoływane zadanie) z kolejki wywołania? (To pytanie jest związane z pytaniem 3)

+0

Dlaczego chcesz/potrzebujesz runloopa na wątku tła? Jeśli opisujesz, co próbujesz zrobić, możemy zaproponować lepsze wzorce. – Rob

+0

@Rob, Nie mówię, że potrzebuję runloopa na tle wątku, jestem po prostu zakłopotany, dlatego zadaję te pytania. Nie jestem pewien, czy każdy wątek ma NSRunLoop w systemie iOS/OSX. –

+0

OK. Podsumowując, nie potrzebujesz (ani koniecznie chcesz) uruchamiać pętli w każdym wątku. Celem pętli uruchamiania jest utrzymanie wątku przy życiu, odpytywanie o zdarzenia. Jest to niemal sprzeczne z wzorami GCD. – Rob

Odpowiedz

14
  1. na głównej pętli wątku prowadzony jest etap, w którym ma pracować wszystkie bloki w kolejce na głównej kolejki. Przydaje się przydatna funkcja this answer, jeśli chcesz zrozumieć, co dokładnie robi pętla uruchamiania.

  2. GCD tworzy wątki dla równoległych kolejek. Wątek nie ma pętli uruchamiania, dopóki po raz pierwszy coś uruchomionego w wątku nie prosi o uruchomienie pętli wątku, w którym to momencie system tworzy pętlę uruchamiania dla wątku. Jednak pętla uruchamiania działa tylko wtedy, gdy coś w tym wątku następnie prosi o uruchomienie (przez wywołanie -[NSRunLoop run] lub CFRunLoopRun lub podobne). Większość wątków, w tym wątków utworzonych dla kolejek GCD, nigdy nie ma pętli uruchamiania.

  3. GCD zarządza pulą wątków i, gdy musi uruchomić blok (ponieważ został dodany do kolejki), GCD wybiera wątek, na którym ma zostać uruchomiony blok. Algorytm wybierania wątków GCD jest głównie szczegółem implementacji, z tym wyjątkiem, że zawsze wybierze główny wątek dla bloku, który został dodany do głównej kolejki. (Zauważ, że NWD będzie również czasem korzystać z głównego wątku bloku dodany do innej kolejki.)

  4. można dostać tylko pętlę biegu głównego wątku (używając +[NSRunLoop mainRunLoop] lub CFRunLoopGetMain) lub pętlę przebiegu prądu wątek (przy użyciu +[NSRunLoop currentRunLoop] lub CFRunLoopGetCurrent). Jeśli potrzebujesz pętli uruchamiania jakiegoś dowolnego wątku, musisz znaleźć sposób, aby zadzwonić pod numer CFRunLoopGetCurrent i przekazać jego wartość powrotną z powrotem do wątków w bezpieczny, zsynchronizowany sposób.

    Należy pamiętać, że interfejs NSRunLoop nie jest wątek bezpieczne, ale CFRunLoop interfejs jest wątek bezpieczne, więc jeśli chcesz mieć dostęp do pętli uruchomienie kolejnego wątku, należy użyć interfejsu CFRunLoop.

    Należy również pamiętać, że prawdopodobnie nie należy uruchamiać pętli uruchamiania przez bardzo długi czas w bloku działającym w kolejce GCD, ponieważ tworzy się wątek, który GCD ma kontrolować. Jeśli musisz uruchomić pętlę uruchamiania przez długi czas, powinieneś uruchomić dla niej własny wątek. Możesz zobaczyć przykład tego w the _legacyStreamRunLoop function in CFStream.c. Zwróć uwagę, w jaki sposób udostępnia pętlę uruchamiania dedykowanego wątku w zmiennej statycznej o nazwie sLegacyRL, którą inicjuje pod ochroną dispatch_semaphore_t.

+0

Dziękuję za wyjaśnienia, przeczytam linki, które podałeś, a jeśli pojawią się jakieś pytania, tutaj skomentuję. –

+0

Czy możesz rozwinąć na "Uwaga, że ​​GCD będzie czasami używać głównego wątku dla bloku dodanego do innej kolejki." Czy to dotyczy rzeczy typu UI? – guptron

+0

Z ['dispatch_sync' dokumentacji] (https://developer.apple.com/documentation/dispatch/1452870-dispatch_sync):" Jako optymalizacji funkcja ta wywołuje blok w bieżącym wątku, gdy to możliwe. " –

3
  1. Zależność pomiędzy pętlą uruchomić główny wątek i głównego kolejki wysyłkowy jest jedynie, że oboje run w głównym wątku i który blokuje wysyłane do głównego kolejka jest przeplatana w wątku głównym z zdarzeniami przetworzonymi w głównym runloopie.

    Jako Concurrency Programming Guide mówi:

    Główną kolejka wysyłka jest dostępna globalnie kolejka seryjny, który wykonuje zadania na głównym wątku aplikacji. Ta kolejka działa z pętlą uruchamiania aplikacji (jeśli jest obecna), aby przeplatać wykonywanie zadań w kolejce z wykonaniem innych źródeł zdarzeń dołączonych do pętli uruchamiania. Ponieważ działa on w głównym wątku aplikacji, główna kolejka jest często używana jako kluczowy punkt synchronizacji dla aplikacji.

  2. Wysyłając do wątku tła, robi nie stworzyć NSRunLoop dla tych wątków roboczych. Zwykle nie potrzebujesz pętli uruchamiania dla tych wątków w tle.Kiedyś musieliśmy tworzyć własne NSRunLoop dla wątków tła (np. Podczas planowania NSURLConnection na wątku tła), ale ten wzór nie jest już często wymagany.

    Dla rzeczy historycznie wymagających pętli uruchamiania, często są lepsze mechanizmy, jeśli działają na wątku w tle. Na przykład zamiast NSURLConnection użyjesz teraz NSURLSession. Lub, zamiast NSTimer na NSRunLoop w wątku tła, należy utworzyć źródło wysyłki timera GCD.

  3. W odniesieniu do tego, kto "zna" wątek, wątek roboczy jest identyfikowany podczas wywoływania do kolejki. Wątek nie jest własnością kolejki, ale jest przypisywany do kolejki, gdy kolejka tego potrzebuje.

  4. Jeśli chcesz utworzyć NSRunLoop dla wątku roboczego (co zresztą i tak nie powinno być robione), możesz go utworzyć i śledzić samodzielnie. Podczas planowania wątku z pętlą uruchomieniową, byłbym skłonny do samodzielnego utworzenia NSThread i zaplanowania pętli uruchamiania zamiast wiązania jednego z wątków roboczych GCD.

+0

O 4. Moje główne pytanie nie dotyczy tego, jak utworzyć/utworzyć NSRunLoop dla wątku roboczego. Chcę zapytać, czy każdy wątek (utworzony przez GCD przy wysyłaniu zadania) ma NSRunLoop? Jeśli tak, jak mogę uzyskać ten NSRunLoop z kolejki wysyłkowej? –

+1

Każdy wątek nie ma własnej pętli uruchamiania, więc ogólnie nie ma niczego do odzyskania. Istnieje metoda pobierania głównej pętli, ale poza tym jedynymi pętlami uruchomieniowymi są te, które samodzielnie utworzyłeś. – Rob