ios - necesita algunas aclaraciones sobre la cola de envío, el subproceso y NSRunLoop
multithreading grand-central-dispatch (2)
El bucle de ejecución del hilo principal tiene un paso en el que ejecuta todos los bloques en cola en la cola principal. Es posible que encuentre útil esta respuesta si desea comprender en detalle lo que hace el bucle de ejecución.
GCD crea los hilos para colas concurrentes. Un subproceso no tiene un bucle de ejecución hasta que la primera vez que algo se ejecuta en el subproceso solicita el bucle de ejecución del subproceso, en cuyo punto el sistema crea un bucle de ejecución para el subproceso. Sin embargo, el bucle de ejecución solo se ejecuta si algo en ese hilo luego le pide que se ejecute (llamando
-[NSRunLoop run]
oCFRunLoopRun
o similar). La mayoría de los subprocesos, incluidos los creados para las colas de GCD, nunca tienen un bucle de ejecución.GCD administra un grupo de subprocesos y, cuando necesita ejecutar un bloque (porque se agregó a alguna cola), GCD selecciona el hilo en el que se ejecuta el bloque. El algoritmo de selección de hilos de GCD es principalmente un detalle de implementación, excepto que siempre elegirá el hilo principal para un bloque que se agregó a la cola principal. (Tenga en cuenta que GCD a veces también usará el hilo principal para un bloque agregado a alguna otra cola).
Solo puede obtener el bucle de ejecución del hilo principal (usando
+[NSRunLoop mainRunLoop]
oCFRunLoopGetMain
) o el bucle de ejecución del hilo actual (usando+[NSRunLoop currentRunLoop]
oCFRunLoopGetCurrent
). Si necesita el bucle de ejecución de algún subproceso arbitrario, debe encontrar una manera de llamar aCFRunLoopGetCurrent
en ese subproceso y pasar su valor de retorno a través de los subprocesos de una manera segura y sincronizada.Tenga en cuenta que la interfaz
NSRunLoop
no es segura para subprocesos, pero la interfazCFRunLoop
es segura para subprocesos, por lo que si necesita acceder al bucle de ejecución de otro subproceso, debe usar la interfazCFRunLoop
.También tenga en cuenta que probablemente no debería ejecutar un bucle de ejecución durante mucho tiempo dentro de un bloque que se ejecuta en una cola de GCD, porque está atando un hilo que GCD espera controlar. Si necesita ejecutar un bucle de ejecución durante mucho tiempo, debe iniciar su propio subproceso para ello. Puede ver un ejemplo de esto en la función _legacyStreamRunLoop en CFStream.c . Observe cómo hace que el bucle de ejecución del subproceso dedicado esté disponible en una variable estática llamada
sLegacyRL
, que se inicializa bajo la protección de undispatch_semaphore_t
.
Las siguientes cosas son lo que sé y entiendo:
La cola global es una cola simultánea que puede enviar tareas a varios subprocesos. El orden de ejecución de la tarea no está garantizado. p.ej:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), {
for (int i; i<10; i++) {
doTask()
}
})
Si quiero enviar a la cola serial , puedo usar
dispatch_async(dispatch_queue_create("my.serial.queue", nil) {
...
}
cada vez solo se envía una tarea a un hilo y se ejecuta. El pedido es FIFO.
===== Lo que estoy confundido y no entiendo completamente =======
El hilo principal tiene un NSRunLoop, tareas de bucle en el hilo principal. Me pregunto cuál es la relación entre la cola de envío y el bucle de ejecución. ¿Puedo entenderlo como, si al enviar una tarea al subproceso principal, el NSRunLoop del subproceso principal obtiene la tarea enviada y la ejecuta?
¿Qué pasa con la cola global que despacha tareas a múltiples hilos? ¿El sistema iOS / OSX crea automáticamente no solo los subprocesos, sino que también crea NSRunLoop para cada subproceso? y luego el bucle de ejecución en cada hilo obtiene la tarea enviada de la cola global y la ejecuta?
¿Quién sabe el hilo? ¿Las funciones
dispatch_async()
ydispatch_sync()
saben a qué hilo enviar la tarea o la cola sabe a qué hilo enviar la tarea?¿Hay una manera de obtener el objeto NSRunLoop del subproceso (al que se envía la tarea) de la cola de envío mediante programación? (esta pregunta está relacionada con la pregunta 3)
La relación entre el bucle de ejecución del subproceso principal y la cola de envío principal es simplemente que ambos se ejecutan en el subproceso principal y que los bloques enviados a la cola principal se intercalan en el subproceso principal con eventos procesados en el bucle principal.
Como dice la Guía de Programación de Concurrencia :
La cola de envío principal es una cola serie disponible globalmente que ejecuta tareas en el hilo principal de la aplicación. Esta cola funciona con el bucle de ejecución de la aplicación (si está presente) para intercalar la ejecución de tareas en cola con la ejecución de otros orígenes de eventos adjuntos al bucle de ejecución. Debido a que se ejecuta en el subproceso principal de su aplicación, la cola principal se usa a menudo como un punto clave de sincronización para una aplicación.
Cuando se envía a un subproceso en segundo plano, no crea un
NSRunLoop
para esos subprocesos de trabajo. Tampoco necesita generalmente un bucle de ejecución para estos subprocesos de fondo. Solíamos tener que crear nuestro propioNSRunLoop
para subprocesos en segundo plano (por ejemplo, al programarNSURLConnection
enNSURLConnection
en segundo plano), pero este patrón ya no es necesario con mucha frecuencia.Para cosas que históricamente requieren bucles de ejecución, a menudo hay mejores mecanismos si se ejecutan en un hilo de fondo. Por ejemplo, en lugar de
NSURLConnection
, ahora usaríaNSURLSession
. O, en lugar deNSTimer
enNSRunLoop
en un subproceso en segundo plano, crearía una fuente de envío de temporizador GCD.Con respecto a quién "sabe" el subproceso, el subproceso de trabajo se identifica cuando se envía a una cola. El hilo no es una propiedad de la cola, sino que se asigna a la cola cuando la cola lo necesita.
Si desea crear un
NSRunLoop
para un subproceso de trabajo (que de todos modos, en general, no debería estar haciendo), puede crearlo y realizar un seguimiento del mismo. Y, al programar un subproceso con un bucle de ejecución, me gustaría crear elNSThread
y programar el bucle de ejecución en eso, en lugar de atar uno de los subprocesos de trabajo de GCD.