La principale distinzione, come fai notare nella tua domanda, è se lo scheduler prevarrà o meno un thread. Il modo in cui un programmatore pensa alla condivisione di strutture di dati o alla sincronizzazione tra "thread" è molto diverso nei sistemi preventivi e cooperativi.
In un sistema cooperativo (che va da molti nomi, cooperative multitasking , nonpreemptive multitasking , thread a livello utente , fili verdi , e le fibre sono cinque quelli comuni attualmente) il programmatore è garantito che il loro codice verrà eseguito atomicamente finché non effettuano chiamate di sistema o chiamate yield(). Ciò rende particolarmente facile gestire le strutture dati condivise tra più fibre. A meno che non sia necessario effettuare una chiamata di sistema come parte di una sezione critica, non è necessario contrassegnare le sezioni critiche ( ad esempio con mutex locke unlockchiamate). Quindi in codice come:
x = x + y
y = 2 * x
il programmatore non deve preoccuparsi che qualche altra fibra possa lavorare contemporaneamente con le variabili xe y. xe yverrà aggiornato atomicamente insieme dal punto di vista di tutte le altre fibre. Allo stesso modo, tutte le fibre potrebbero condividere una struttura più complicata, come un albero e una chiamata come tree.insert(key, value)non dovrebbe essere protetta da alcun mutex o sezione critica.
Al contrario, in un sistema multithreading preventivo, come con thread realmente paralleli / multicore, è possibile ogni possibile interlacciamento di istruzioni tra thread a meno che non vi siano sezioni critiche esplicite. Un'interruzione e una prelazione potrebbero diventare tra due istruzioni qualsiasi. Nell'esempio sopra:
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
Quindi, per essere corretti su un sistema preventivo, o su un sistema con thread veramente paralleli, è necessario circondare ogni sezione critica con una sorta di sincronizzazione, come un mutex lockall'inizio e un mutex unlockalla fine.
Le fibre sono quindi più simili alle librerie di I / O asincrone che ai thread preventivi o ai thread veramente paralleli. Lo scheduler delle fibre viene richiamato e può cambiare fibra durante le operazioni di I / O a lunga latenza. Ciò può offrire il vantaggio di più operazioni di I / O simultanee senza richiedere operazioni di sincronizzazione in sezioni critiche. Pertanto, l'uso delle fibre può forse avere una minore complessità di programmazione rispetto ai thread preventivi o veramente paralleli, ma la mancanza di sincronizzazione attorno alle sezioni critiche porterebbe a risultati disastrosi se si provasse a far funzionare le fibre in modo simultaneo o preventivo.