2012-02-04 11 views
16

Me han encargado en una clase crear una biblioteca de subprocesos de nivel de usuario en C. Me preguntaba si alguien podría darme una lista de cosas que leer para lograr esto. Tengo una buena idea en cuanto a dónde comenzar, pero cualquier recurso en los subprocesos de nivel de usuario y algunos aspectos aplicables del lenguaje C que podrían ayudar serían extremadamente valiosos.Implementación de un paquete de subprocesos de nivel de usuario

No tengo muy claro cómo implementaría un planificador para tal. Supongamos que entiendo muy bien el lenguaje C y algunas de sus funciones de biblioteca más útiles.

+4

La asignación es un poco difícil de cumplir porque no se puede hacer "en C". Necesita al menos una cantidad mínima de ensamblados o extensiones de compilador equivalentes para facilitar la creación de nuevos contextos de ejecución y el cambio entre ellos. O podría escribir su propia máquina virtual completa e implementación C para ejecutar en la máquina virtual, pero no creo que esto sea lo que su instructor tenía en mente ... –

+1

Para la multitarea/subprocesamiento cooperativo, puede encontrar getcontext/makecontext/setcontext funciones útiles. – MetallicPriest

+0

No puedo ver cómo podría hacerse esto sin algún ensamblador para implementar el guardado/restauración del contexto de registro y el puntero de la pila. Eso sin siquiera considerar la E/S y cómo esperarla. –

Respuesta

8

He hecho esto para una tarea sin escribir ningún ensamblador. El mecanismo de cambio de hilo fue setjmp/longjmp. Lo que esto implicaba era asignar memoria para la pila de cada hilo, luego masajear muy cuidadosamente los valores en el jmp_buff para que la ejecución salte a la pila del siguiente hilo.

Ver también Russ Cox bastante legible libtask.

Edite en respuesta al comentario de OP: Al decidir cuándo cambiar los hilos hay dos direcciones principales: preventiva & cooperativa. En el modelo preventivo, tendrá algo así como una señal de temporizador que hace que el flujo de ejecución salte a un hilo de despachador central, que elige el siguiente hilo para ejecutar. En un modelo cooperativo, los subprocesos "ceden" mutuamente, explícitamente (, por ejemplo,, llamando a una función yield() que proporcionará) o implícitamente (, por ejemplo,, solicitando un bloqueo retenido por otro subproceso).

Eche un vistazo a la API de libtask para ver un ejemplo del modelo cooperativo, particularmente la descripción de la función taskyield(). Ese es el rendimiento explícito que mencioné. También existen las funciones de E/S sin bloqueo que incluyen un rendimiento implícito: la "tarea" actual se pone en espera hasta que se completa la E/S, pero las otras tareas tienen la oportunidad de ejecutarse.

+0

Así es como me imaginé que haría el cambio de hilo. Supongo que mi mayor falta de conocimiento es cómo determinar cuándo un hilo debe renunciar al control para que otro pueda ejecutarse. es decir, cómo determinan los hilos que han tenido suficiente tiempo. – SirensOfTitan

+0

@SirensOfTitan, actualicé mi respuesta para cubrir lo que acaba de preguntar. –

4

Un planificador cooperativa sencilla se puede hacer en C usando swapcontext, mira el ejemplo en la página del manual swapcontext here, se trata de su producción:

$ ./a.out 
main: swapcontext(&uctx_main, &uctx_func2) 
func2: started 
func2: swapcontext(&uctx_func2, &uctx_func1) 
func1: started 
func1: swapcontext(&uctx_func1, &uctx_func2) 
func2: returning 
func1: returning 
main: exiting 

Así como se puede ver que es bastante factible.

Nota: si cambia el contexto dentro de un manejador de señal de temporizador, entonces usted mismo tiene un programador preventivo, pero no estoy seguro de si es seguro o posible hacer esto.

Editar: Encontré esto en la página del manual de sigaction lo que sugiere que es posible cambiar el contexto dentro de un manejador de señales:

Si SA_SIGINFO se especifica en sa_flags, entonces sa_sigaction (en lugar de sa_handler) especifica la función de manejo de señal para signum. Esta función recibe el número de señal como primer argumento, un puntero a siginfo_t como su segundo argumento y un puntero a ucontext_t (emitido a void *) como su tercer argumento.

+1

Dado que este es un problema de tarea (y lo he retenido), el OP debería verificar si eso sería aceptable. Lo más probable es que el instructor esté buscando una implementación de la funcionalidad 'swapcontext()' en lugar de simplemente usarla. –

1

Puede buscar la implementación de código abierto de Apple. Tenga en cuenta que la mayor parte del código es en realidad código de ensamblaje, porque requiere algunas cosas especializadas que no puede hacer en C, como recuperar la dirección de retorno del marco de pila o saltar a una dirección arbitraria.

Los hilos de Userland (también llamados comúnmente "fibras") generalmente emplean un modelo cooperativo; es decir, los subprocesos se ejecutan hasta que deciden que ya tuvieron suficiente tiempo, luego ceden a otro subproceso. Con una cola de prioridad, puede implementar un planificador que ejecute la tarea que se ha ejecutado durante el menor tiempo posible. (El programador realiza un seguimiento de las tareas en ejecución, y la tarea en ejecución cede cuando decide que ya se ha tenido suficiente. El planificador actualiza la cantidad de tiempo que la tarea se ha ejecutado y luego cede a la que tuvo el menor tiempo de ejecución).

Cuestiones relacionadas