Funzioni pre / post multithread

1

Sto programmando un'applicazione per un dispositivo incorporato. Stiamo usando un RTOS che supporta il multi threading. Il dispositivo dovrebbe imitare un progetto precedente che è stato programmato in modalità C (senza fili).

Il progetto originale utilizza una pila e le funzioni START / END all'inizio e alla fine di ogni funzione che può essere richiamata durante il runtime. Ogni volta che START viene chiamato un numero costante (identificando la funzione) verrà messo in pila - END lo rimuoverà dallo stack e controllerà se la parte superiore è uguale alla funzione chiamata. Se è diverso è successo qualcosa di veramente brutto e il dispositivo si ripristinerà / ripristinerà.

Questa funzione è ottima per scopi di debug in quanto mostra completamente come vengono chiamate le funzioni. Sarebbe molto bello avere una funzione simile nella versione multi-thread.

Ho implementato START e END come una classe in C ++ usando il costruttore e il distruttore che rende la gestione abbastanza facile. Esecuzione di questo lavoro a thread singolo come un fascino. Qualsiasi cosa multithreading distruggerà lo stack mentre lo scheduler cambia contesto e scrivere in uno stack non avrebbe senso.

La soluzione più semplice nella mia mente sarebbe avere uno stack START / END per ogni thread - > Problema ogni funzione deve sapere su quali thread viene eseguito. C'è una soluzione migliore a questo problema?

    
posta clambake 28.08.2014 - 10:47
fonte

1 risposta

1

(Si prega di notare che nei commenti sopra, l'OP ha menzionato lo "stack" di cui stiamo parlando non è lo stack delle chiamate, è uno stack dedicato separato per lo scopo del monitoraggio delle chiamate)

Abbiamo già trattato il concetto di Thread Local Storage (TLS) nei commenti sopra. Se è disponibile e vuoi usarlo, ottimo.

Un altro approccio è leggermente più "roll your own", ma l'ho usato con successo. Per ora, presumo che stiamo parlando solo del tracciamento delle chiamate delle funzioni a livello di attività, sebbene questo metodo possa essere esteso anche agli ISR.

La maggior parte delle RTOS offre l'opportunità di eseguire funzioni di callout definite dall'utente, o "hook", in punti specifici, come entrare in & uscita da ISR, cambio di contesto in entrata e in uscita da un'attività, tick del timer, ecc. Ad esempio, FreeRTOS fornisce un ampio set di [Trace Macros] ( link ) che ti consente di utilizzare lo strumento & traccia il tuo codice (vedi traceTASK_SUSPEND(xTask) e traceTASK_RESUME(xTask) , ad esempio.)

Manteniamo questo semplice. Odio i globals, sono un bug di origine, interrompono l'incapsulamento, ecc. Detto questo, potresti avere una variabile globale:

FUNC_CALL_STK   *stack_ptr;

o qualsiasi altra cosa. Ogni volta che si passa a un'attività (utilizzando la funzione di hook incorporato di RTOS), "stack_ptr" viene impostato sulla posizione "stack di traccia" dell'attività corrente. Ogni volta che si esce dall'attività (di nuovo, tramite hook RTOS), si memorizza stack_ptr nel puntatore dello stack privato dell'attività. Ogni attività ha il proprio stack di tracciamento privato & puntatore nella posizione corrente.

Un'altra alternativa, che evita di utilizzare le funzioni di hook fornite dal sistema operativo (io tendo a favorire questo approccio):

Ogni attività avrebbe ancora il suo stack di tracciamento e amp; puntatore, ma questo potrebbe essere implementato come una tabella di ricerca di "puntatori dello stack" (forse indicizzati dall'ID dell'attività o da qualsiasi altra cosa), e basta usare quelli direttamente dal contesto dell'attività per spingere & pop. Stack di tracciamento di ogni attività & il puntatore dello stack verrebbe inizializzato all'avvio dell'attività, prima di entrare nel "ciclo infinito" dell'attività. Ad esempio, la tua funzione START farebbe qualcosa del tipo:

PushCurrentFuncIdentifier(FuncId, GetCurrentTaskID());

GetCurrentTaskID() è un'API del sistema operativo che restituirebbe un numero intero che identifica in modo univoco l'attività attualmente in esecuzione (ogni RTOS ha una tale API). Non importa se / quando si verifica un cambio di contesto, questo dovrebbe essere thread-safe.

BTW, usando la tua classe C ++, CTOR potrebbe salvare l'ID Task (TID) come membro privato, e quindi il DTOR potrebbe usare il TID memorizzato nella cache invece di dover chiamare di nuovo l'API RTOS.

    
risposta data 01.09.2014 - 21:48
fonte

Leggi altre domande sui tag