2013-03-20 24 views
13

Ho trovato un certo codice in FreeRTOS (FreeRTOSV7.4.0 \ FreeRTOS \ Source \ tasks.c):L'incremento automatico nel thread C è sicuro?

void vTaskSuspendAll(void) 
{ 
    /* A critical section is not required as the variable is of type 
    portBASE_TYPE. */ 
    ++uxSchedulerSuspended; 
} 

è esplicitamente detto no necessità di proteggere a causa del tipo è "portBASE_TYPE", che è una " lungo "tipo. La mia comprensione è che presuppone che l'auto-incremento di questo tipo sia atomico. Ma dopo che l'ho smontato non ho trovato nessuna prova, è un semplice carico-> add-> store. Allora è un problema?

void vTaskSuspendAll(void) 
{ 
     /* A critical section is not required as the variable is of type 
     portBASE_TYPE. */ 
     ++uxSchedulerSuspended; 
4dc: 4b03   ldr  r3, [pc, #12] ; (4ec <vTaskSuspendAll+0x10>) 
4de: f8d3 2118  ldr.w r2, [r3, #280] ; 0x118 
4e2: 1c50   adds r0, r2, #1 
4e4: f8c3 0118  str.w r0, [r3, #280] ; 0x118 
4e8: 4770   bx  lr 
4ea: bf00   nop 
4ec: 00000000  .word 0x00000000 

000004f0 <xTaskGetTickCount>: 
     return xAlreadyYielded; 
} 
+7

Non è definito da C. Dipende dalla piattaforma di compilatore/hardware. –

+1

Una buona politica da adottare quando si ha a che fare con la sicurezza del thread è questa: se c'è anche il più piccolo brandello di una possibilità che si verifichi una condizione di competizione, allora si verificherà. Questo non risponde alla tua domanda, ma è utile per rassicurarti che il blocco è importante se ti trovi mai a pensare "questa operazione è così quasi atomica che non ho bisogno di bloccare". – paddy

+0

Infine, trovo il motivo per cui è sicuro qui. Ringrazia tutti! [link] (http://www.freertos.org/FreeRTOS_Support_Forum_Archive/February_2010/freertos_portBASE_TYPE_amp_critical_section_3560405.html) – user1603164

risposta

7

No, i valori incrementali in C non sono garantiti per essere atomici. È necessario fornire la sincronizzazione o utilizzare una libreria specifica del sistema per eseguire incrementi/decrementi atomici.

+0

Quindi vuoi dire che può essere un bug? Anche in un ambiente single core? – user1603164

+1

@ user1603164 * Se * il contesto può essere preimpostato nell '"area critica". –

+1

@ user1603164 Assolutamente: se il codice è preimpostato tra il caricamento e la memorizzazione del valore, l'altro thread può modificare il valore da sotto, causando problemi trovare errori Questo accadrebbe anche in ambienti single-CPU, single-core, non-hyperthreaded. – dasblinkenlight

6

Non è atomico, come hai documentato. Ma potrebbe ancora essere "thread safe" in un senso meno rigoroso: uno long non può essere in uno stato incoerente. L'entità del pericolo qui è che se i thread n chiamano vTaskSuspendAll allora uxSchedulerSuspended verrà incrementato da qualsiasi punto tra 1 e n.

Ma questo potrebbe essere perfetto se la variabile è qualcosa che non ha bisogno di essere perfetta, come un tracker per quante volte l'utente ha chiesto di sospendere. C'è "thread safe" che significa "questa operazione produce lo stesso risultato, indipendentemente da come le sue chiamate sono intercalate" e c'è "thread safe" che significa "niente esplode se lo chiamate da più thread".

+0

+1 per la risposta più completa. Penso che il commento nel codice FreeRTOS originale sia fonte di confusione. Scommetto che tutto ciò che FreeRTOS richiede è che uxSchedulerSuspended non sia zero da fermare, quindi non importa se viene incrementato 1 o n. –

5

L'operazione non è atomica, ma da nessuna parte dice che lo è. Tuttavia, il codice è thread-safe, ma dovresti avere molta familiarità con ciò che stava facendo il codice e come è stato adattato al design dello scheduler per saperlo. Non importa se altre attività modificano la variabile tra il carico e l'archivio perché quando l'attività di esecuzione successiva viene eseguita, troverà la variabile nello stesso stato di quando è stato eseguito il caricamento originale (quindi le parti di modifica e scrittura sono ancora coerenti e valide).

Come note precedenti, il lungo non può essere in uno stato incoerente perché è il tipo di base dell'architettura su cui è in esecuzione. Si consideri tuttavia cosa succederebbe se il codice fosse in esecuzione su una macchina a 8 bit (o 16 bit) e la variabile fosse a 32 bit. Quindi non sarebbe thread-safe perché i 32 bit completi sarebbero modificati byte o word alla volta, piuttosto che tutti in una volta. In tale scenario, un byte può essere caricato in un registro, modificato, quindi riscritto nella RAM (lasciando gli altri tre byte non modificati) quando si verifica un cambio di contesto. Se l'attività successiva che eseguiva leggeva la stessa variabile, avrebbe letto un byte che era stato modificato e tre byte che non lo erano e avresti un grosso problema.

saluti, Richard (http://www.FreeRTOS.org)

+0

+1 Se la variabile è garantita nello stesso stato quando viene eseguita l'attività successiva, perché questa stessa ipotesi non dovrebbe essere mantenuta per l'incremento di un tipo multi-byte? – dasblinkenlight