Pattern modulo in C con threading - dove controllare i thread?

1

Quindi sto lavorando su un programma C in crescita in un ambiente Linux / POSIX, e mi sono imbattuto in un'area in cui non sono abbastanza sicuro su come procedere.

Fondamentalmente, sto usando un modello di modulo per sviluppare il mio codice da utilizzare con diversi hardware esterni e operazioni di I / O (ad esempio: un modulo file, un modulo videocamera, un modulo seriale, ecc.) Alcune di queste operazioni prenditi un po 'di tempo per completarlo, e dovresti metterlo nella loro stessa discussione per ovvi motivi.

La mia domanda si riduce fondamentalmente a questo: I moduli stessi dovrebbero controllare il threading sulle operazioni interne, o se il codice chiamante "above" ogni modulo implementa il threading sulle stesse funzioni.

Da un lato, posso vedere dal punto di vista della complessità che dover controllare il threading di più moduli da un punto centrale può essere un po 'un casino. Tuttavia, se il modulo implementa il threading su se stesso, perdi il contesto e il controllo dei singoli processi. Un compromesso potrebbe essere l'esposizione degli oggetti thread tramite il file di intestazione dell'interfaccia, ma poi ritengo che potresti tornare al primo passaggio di nuovo.

I moduli sono attualmente progettati come un blocco funzionale astratto di codice, con poca esposizione al di fuori delle variabili di configurazione (quindi sarebbe una generica interfaccia "Camera" con diversi moduli che implementano l'hardware di quella specifica build o revisione). Le operazioni di I / O non sono intensive, ma tendono a richiedere un po 'di tempo per essere completate; quindi una possibilità potrebbe essere usare una variabile bool / enum esposta per indicare lo stato?

    
posta au42 27.09.2017 - 08:49
fonte

2 risposte

1

L'opzione migliore è utilizzare entrambi gli approcci, ma essere molto consapevoli di garantire che i thread siano noti solo al loro proprietario.

L'obiettivo per ogni modulo è:

  • Ogni modulo dovrebbe essere utilizzabile stand-alone.
  • Ogni modulo non dovrebbe preoccuparsi di quali altri moduli lo stanno usando.
  • Ogni modulo dovrebbe renderlo il più semplice possibile da utilizzare correttamente. Il che significa che non dovrebbe fare affidamento sul chiamante per usarlo correttamente. Dovrebbe fornire un'interfaccia che lo rende davvero difficile da usare in modo errato.

Il modo più semplice per ottenere questi punti elenco è rendere il blocco delle API del modulo e sincrono. Ciò non significa che il modulo non debba utilizzare il threading o che abbia threading gestito esternamente. Significa che il modulo deve utilizzare il threading interno dietro l'API, quindi tenerlo nascosto all'utente API e fare in modo che la chiamata alla funzione appaia sincrona all'utente.

Il blocco e la sincronizzazione funzionano la maggior parte del tempo ma certamente non sempre. Nei casi in cui le chiamate richiedono troppo tempo o sincrono non è una buona opzione, rendere l'API asincrona del modulo può essere una buona scelta. Detto questo, questo aggiunge complessità al codice chiamante, quindi anche se un'API ha chiamate che potrebbero richiedere molto tempo, potrebbe essere comunque preferibile lasciare il blocco dell'interfaccia se il chiamante sta già gestendo le operazioni di livello superiore che chiamano l'interfaccia.

Parlando di operazioni di livello superiore, il problema con il solo focalizzarsi su come le API del modulo incorporano il threading è che le operazioni dei moduli tendono ad essere solo una parte di un'operazione di sistema più completa. Pertanto, è necessario che il codice chiamante debba anche gestire il proprio threading per coordinare l'elaborazione a lungo termine. Per ottenere un'integrazione perfetta, è molto importante che i thread dei moduli siano sconosciuti al codice del chiamante / livello superiore e allo stesso modo i moduli non sappiano nulla dei thread del chiamante.

    
risposta data 28.09.2017 - 23:45
fonte
3

Molto probabilmente, vorrai che il programma principale gestisca i thread e ciascun modulo esegua semplicemente la sua funzione. Per fare ciò, dovrai definire un'API che i moduli devono supportare. Il programma principale richiamerebbe una funzione da questa API all'avvio del thread, forse un secondo da ripulire dopo che il thread è stato terminato o annullato, e un terzo che riporta l'avanzamento del thread, in modo che il programma principale possa visualizzare un progresso metro.

Il modo più semplice per essere sicuri è di eliminare due dei moduli presumendo che i moduli faranno tutta la gestione dei thread. Qualsiasi codice copiato / incollato dal primo modulo quando si scrive il secondo è un buon candidato da refactoring nel gestore thread nel programma principale.

    
risposta data 28.09.2017 - 00:52
fonte