freeRTOS C ++ 11 coda con puntatori all'interno, orientata agli oggetti

0

Ho pensato a questo problema che stavo vivendo. Ho un design di tipo produttore-consumatore con due mittenti di compiti creati dall'utente e lettore. La coda viene utilizzata per comunicare tra il lettore-mittente. Attualmente la cosa funziona, ma sto inviando una struttura grezza nella coda, che contiene tutti i possibili datamembers per ogni possibile Gcodecommand.

Stavo pensando a una soluzione diversa, come segue ... Fondamentalmente sto ancora facendo un brainstorming a questo punto ... Un po 'come la conversazione gommosa in programmazione ...

Ho diversi tipi di comandi Gcode, che dovrebbero essere probabilmente classi diverse (i datamembers sono di numero variabile, ma sono combinazioni di bool e di interi)

esempi per le classi:

  • comando M1, bool isLegal
  • Comando M2, bool isLegal, int pencilServoValue
  • Comando G1, bool isLegal, int XcoordHundredths, YcoordHundredths
  • Comando M5, bool isLegal, bool XMotorClockwise, bool YMotorClockwise, int height, int width, int speed
  • ecc ...

Forse potrei avere un altro oggetto avvolto, che in realtà è il tipo di oggetto che viene inviato in coda.

  • dataPacket, enum {M1, M2, G1 ...} baseType, void * commandAddress

Non sono sicuro che tu sia autorizzato a usare un puntatore vuoto come quello ... Preferirei avere un datamember di puntatore all'interno di dataPacket, ma dovrebbe essere in grado di accettare qualsiasi "Puntatore di comando" come datamember, ovviamente ...

Questo significa che dovrei ereditare tutti i comandi Gcode da una classe di riferimento comune e avere un puntatore di classe base come datamember dataPacket?

SE, faccio questo con il puntatore della classe di base, devo quindi implementare il distruttore in un certo modo, come un distruttore virtuale o qualcosa del genere?

In modo che il distruttore corretto venga sempre chiamato per qualsiasi classe derivata?

Quindi, per un caso d'uso,

Potrei ammucchiare-allocare con un nuovo operatore un comando particolare, e inserire l'indirizzo in dataPacket e configurare il dataPacket con baseType corretto. Heap-allocate proteggerebbe il puntatore, per tutta la sua durata all'interno della coda, immagino ... ma sembra sempre che usare l'allocazione dell'heap sarebbe un po 'lento e inefficiente per il codice?

Quindi, potrei inviare il dataPacket in coda.

Quindi, reader_task può leggere cosa c'è dentro il dataPacket ed eliminare il puntatore per liberare la memoria per evitare perdite di memoria.

Mi chiedevo anche quale sarebbe stato un buon accumulo di tempo per l'uso di FreeRTOS in questo tipo di casi d'uso? Le allocazioni con il nuovo operatore saranno ovviamente un caso comune ... e idealmente, naturalmente, i puntatori dovrebbero essere al sicuro durante il tempo trascorso in attesa all'interno della coda.

Penso che ci sarà un solo produttore e un compito per i consumatori.

    
posta Late347 17.10.2018 - 23:49
fonte

1 risposta

0

Ci sono diversi approcci:

Approcci C ++

  • Approccio di classe base (la classe base astratta non è banale in C ++, ma la maggior parte dei programmatori C ++ può darti uno scheletro dal quale puoi compilare i dettagli di implementazione)
  • Tipo di approccio alla cancellazione (avanzato, facile da sbagliare, non consigliato)
  • Approccio di serializzazione / deserializzazione (richiede più impegno e sarà più lento, più facile da capire per i programmatori che hanno già familiarità con altri linguaggi.)

Approcci in stile C

  • Struttura unione in stile C, oltre a un enum che indica il tipo di comando.
    Osservazione Le classi C ++ non possono essere nidificate in una struttura unione in stile C, perché costruttori, distruttori e metodi virtuali non funzionano quando sono nidificati all'interno di un unione. I compilatori dovrebbero impedire che tale codice venga compilato; ma anche se il compilatore non fornisce alcun avvertimento, il codice generato potrebbe essere solo spazzatura.
  • Una struttura POD (plain old data) che ha tutti i campi (extra); verranno utilizzati solo alcuni campi, a seconda del tipo di comando.

Per tutti gli approcci C ++ (i primi tre), sembra necessario utilizzare l'allocazione dell'heap. Questo perché i diversi comandi sembrano richiedere dimensioni diverse. Tuttavia, se esiste una dimensione di dati massima predefinita, è possibile utilizzarla come dimensione del buffer fissa per l'approccio di serializzazione / deserializzazione.

Gli approcci in stile C richiedono che la dimensione corrisponda alla dimensione massima dei dati o alla somma delle dimensioni di tutti i campi distinti tra tutti i tipi di comando.

Per usare l'approccio alla classe base C ++, il distruttore della classe base deve essere dichiarato virtuale. Questo è tutto.

Creando un distruttore virtuale, C ++ ti permette di cancellare un oggetto di un tipo derivato usando un puntatore il cui tipo è la classe base. In altre parole, il codice responsabile dell'eliminazione dell'oggetto può procedere senza controllo e casting nel tipo derivato.

Mentre cerchi le esercitazioni online, vedrai molte menzioni di "puro distruttore virtuale" o "classe astratta". Secondo me, lo scopo di rendere una classe "astratta" è di impedirne l'istanziazione (ad esempio impedendoti di creare un'istanza di una classe base). Se non ti preoccupi troppo del C ++ "idiomatico", devi solo inserire "virtuale" nella dichiarazione del distruttore.

La cancellazione di tipo è davvero brutta, ma può essere eseguita in C ++ 11 legale. È l'approccio che fa funzionare std::shared_ptr . Inoltre, è possibile che il codice C ++ 11 di qualcuno contenga std::shared_ptr<void> , che sfrutta intenzionalmente la potenza della cancellazione dei tipi. Dato che è davvero troppo brutto, non entrerò nei dettagli, e non lo consiglio in generale. Richiede i modelli C ++, che automatizza la creazione di classi wrapper one-to-one per ogni classe di comando. Le classi wrapper derivano da una classe base comune, lo stesso approccio sopra menzionato, per consentire la cancellazione senza downcasting.

Disclaimer: le mie conoscenze potrebbero essere inaccurate o errate. Continua a leggere e a imparare e a prestare attenzione alle discrepanze nei dettagli che potrebbero indicare errori nella scrittura.

    
risposta data 18.10.2018 - 13:53
fonte

Leggi altre domande sui tag