La distinción principal, como señala en su pregunta, es si el programador alguna vez se adelantará a un hilo. La forma en que un programador piensa en compartir estructuras de datos o en sincronizar entre "hilos" es muy diferente en sistemas preventivos y cooperativos.
En un sistema cooperativo (que va por muchos nombres, de cooperación multi-tarea , nonpreemptive multitarea , las discusiones a nivel de usuario , hilos verdes , y las fibras son cinco de las más comunes en la actualidad) que el programador está garantizado que su código se ejecutará de forma atómica , siempre y cuando No hacen llamadas ni llamadas al sistema yield(). Esto hace que sea particularmente fácil tratar con estructuras de datos compartidas entre múltiples fibras. A menos que necesite realizar una llamada al sistema como parte de una sección crítica, no es necesario marcar las secciones críticas (con mutex locky unlockllamadas, por ejemplo). Entonces en código como:
x = x + y
y = 2 * x
el programador no necesita preocuparse de que alguna otra fibra pueda estar trabajando con las variables xy yal mismo tiempo. xy yse actualizarán juntos atómicamente desde la perspectiva de todas las otras fibras. Del mismo modo, todas las fibras podrían compartir una estructura más complicada, como un árbol y una llamada similar tree.insert(key, value)no necesitaría estar protegida por ningún mutex o sección crítica.
Por el contrario, en un sistema de subprocesamiento múltiple preventivo, como con subprocesos verdaderamente paralelos / multinúcleo, todas las posibles intercalaciones de instrucciones entre subprocesos son posibles a menos que haya secciones críticas explícitas. Una interrupción y una preferencia podrían convertirse entre dos instrucciones. En el ejemplo anterior:
thread 0 thread 1
< thread 1 could read or modify x or y at this point
read x
< thread 1 could read or modify x or y at this point
read y
< thread 1 could read or modify x or y at this point
add x and y
< thread 1 could read or modify x or y at this point
write the result back into x
< thread 1 could read or modify x or y at this point
read x
< thread 1 could read or modify x or y at this point
multiply by 2
< thread 1 could read or modify x or y at this point
write the result back into y
< thread 1 could read or modify x or y at this point
Entonces, para ser correcto en un sistema preventivo, o en un sistema con hilos verdaderamente paralelos, debe rodear cada sección crítica con algún tipo de sincronización, como un mutex lockal principio y un mutex unlockal final.
Por lo tanto, las fibras son más similares a las bibliotecas de E / S asíncronas que a los hilos preventivos o hilos verdaderamente paralelos. Se invoca el planificador de fibra y puede cambiar fibras durante operaciones de E / S de latencia larga. Esto puede brindar el beneficio de múltiples operaciones simultáneas de E / S sin requerir operaciones de sincronización alrededor de secciones críticas. Por lo tanto, el uso de fibras puede, quizás, tener menos complejidad de programación que los hilos preventivos o verdaderamente paralelos, pero la falta de sincronización alrededor de las secciones críticas conduciría a resultados desastrosos si intentara ejecutar las fibras de manera realmente simultánea o preventiva.