Domanda

Recentemente ho progettato una libreria di classi Thread, ho creato una classe astratta Thread come la seguente:

class Thread {
public:
    run() { /*start the thread*/ }
    kill() { /*stop the thread*/ }
protected:
    virtual int doOperation(unsigned int, void *) = 0;
};

Le classi di thread reali erediteranno questa classe astratta e implementerebbero il metodo doOperation nella sua logica, qualcosa di simile a Modello di strategia .

Il problema è che mi affido a una libreria back-end C che definisce l'esecuzione del thread nella seguente funzione:

int startThread(char* name, (int)(*)(unsigned int, void*), int, int, int, void*);

Come puoi vedere; il secondo parametro è un puntatore a funzione del loop del thread (funzione principale), ed ecco il problema; poiché utilizzo questa funzione C per avviare il thread nel metodo run, passo l'indirizzo di reinterpret_cast al secondo parametro e ciò non può essere fatto a causa della mancata corrispondenza del tipo.

Ho provato a usare <=> per restituire un puntatore, ma I ISO-C ++ proibisce di restituire un puntatore di membro di funzione non inizializzato. Non so come superare questo conflitto, l'uso di un metodo statico è l'unica soluzione che immagino, ma fa esplodere il mio modello di progettazione!

È stato utile?

Soluzione

Per prima cosa, assicurati di leggere il link fornito da Michael Burr, in quanto contiene buone informazioni. Quindi, ecco lo pseudo-codice ish C ++ per esso:

int wrapperDoOperation(int v, void *ctx)
{
    Thread *thread = (Thread *)ctx;
    return thread->doOperation(v);
}

class Thread {
public:
    run() {
         startThread("bla", wrapperDoOperation, bla, bla, bla, (void *)this);
    }
    kill() { /*stop the thread*/ }
protected:
    virtual int doOperation(unsigned int) = 0;

friend wrapperDoOperation ......;
};

L'idea è che doOperation, essendo una funzione membro di Thread, non ha bisogno di un contesto vuoto *, puoi semplicemente mantenere qualunque cosa passi come contesto nell'oggetto stesso. Pertanto, è possibile utilizzare il puntatore vuoto per passare l'attuatore questo puntatore a doOperation. Nota che i dettagli del void * sono nascosti agli utenti della tua classe, il che è carino.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top