2012-08-17 31 views
5

sto provando a creare un nuovo thread con una classe "CameraManager" ma ho il seguente errore:non può convertire '* void (MyClass :: *) (void *) in void * (*) (void *) nella funzione pthread_create

cannot convert '*void(CameraManager:: *)(void*) to void*(*)(void*) in pthread_create function

ho definito nel file cameramanager.h:

public: 
void *dequeueLoop(void *ptr); 

e nel cameramanager.cpp

void CameraManager::startDequeuing(){ 
dequeuing = true; 
dequeueThreadId = pthread_create(&dequeueThread, NULL, &CameraManager::dequeueLoop, NULL); 
} 

void *CameraManager::dequeueLoop(void *ptr){ 
while(dequeuing){ 
    highSpeedCamera->dequeue(); 
    highSpeedCamera->enqueue(); 
} 

io non voglio declar e dequeueLoop come funzione statica ho anche provato a dichiarare dequeueLoop come una funzione friend di classe nel modo seguente ma non ha scope sulle variabili di classe 'highSpeedCamera' e 'dequeuing' e il compilatore mi dice anche che 'dequeueLoop' era non dichiarati in questo ambito

per fare dequeueLoop una funzione amico ho fatto:

cameramanager.h

public: 
friend void *dequeueLoop(void *ptr); 

cameramanager.cpp

void CameraManager::startDequeuing(){ 
    dequeuing = true; 
    dequeueThreadId = pthread_create(&dequeueThread, NULL, &CameraManager::dequeueLoop, NULL); 
} 
void *dequeueLoop(void *ptr){ 
    while(dequeuing){ 
     highSpeedCamera->dequeue(); 
     highSpeedCamera->enqueue(); 
    } 
} 

Dove sto sbagliando?

+1

Perché non si desidera rendere una funzione membro statico. Puoi sempre passare 'this' come argomento in modo da ottenere l'accesso ai dati dei membri privati. – pstrjds

risposta

6

I don't want to declare dequeueLoop as a static function

Se si desidera utilizzare pthreads, è necessario disporre di una funzione statica o non membro per il punto di ingresso. È possibile passare un puntatore all'oggetto a questa funzione, usandolo come un trampolino nella funzione membro non statica:

static void * dequeueEntry(void * self) { 
    return static_cast<CameraManager*>(self)->dequeueLoop(); 
} 

dequeueThreadId = pthread_create(
    &dequeueThread, NULL, 
    &CameraManager::dequeueEntry, // <-- pointer to trampoline function 
    this);      // <-- pointer to object for member function 

In alternativa, se si dispone di un compilatore moderno, è possibile utilizzare la libreria di thread standard invece:

std::thread thread(&CameraManager::dequeLoop, this); 
+3

Se non hai un compilatore moderno, puoi considerare boost :: thread - sarà la stessa bella sintassi – nogard

+0

grazie, ho provato la prima implementazione che mi hai suggerito ma quando compilo ho il seguente errore: 'In funzione 'void * dequeEntry (void *)' 'valore vuoto non ignorato come dovrebbe essere' –

+0

@GabrieleGambotto: Sembra che il tuo 'dequeueLoop' non sia dichiarato per restituire nulla, a differenza di quello nella tua domanda che è dichiarato a ritorna 'void *', ma dimentica di restituire qualsiasi cosa. Prendi 'dequeueLoop' per restituire il valore di ritorno del thread, o metti un'istruzione separata' return' in 'dequeueEntry'. –

2

Non è possibile utilizzare un puntatore alla funzione membro come puntatore a funzione a meno che non sia statico. Dovrai rendere dequeueLoop una funzione gratuita o scrivere una funzione gratuita come wrapper.

Per accedere ai membri della classe in una funzione libera, è necessario che la funzione passi il puntatore this come argomento finale di pthread_create. Quindi fare in modo che la funzione libera esegua il suo argomento su un puntatore alla classe.

3

Se si desidera che la funzione sia membro della classe, è static. È perché la funzione thread verrà chiamata direttamente e non avrà un puntatore this valido. Questo può essere risolto da avere una funzione wrapper, che viene passato l'oggetto reale e quindi chiama la funzione membro corretto:

void *dequeueLoopWrapper(void *p) 
{ 
    CameraManager *cameraManager = static_cast<CameraManager*>(p); 
    camereraManager->dequeueLoop(); 
    return nullptr; 
} 

// ... 

void CameraManager::startDequeuing() 
{ 
    dequeuing = true; 
    dequeueThreadId = pthread_create(&dequeueThread, NULL, dequeueLoopWrapper, this); 
} 

Tuttavia, vi consiglio di iniziare a utilizzare il threading support nella nuova libreria standard:

void CameraManager::startDequeuing() 
{ 
    dequeuing = true; 
    myThread = std::thread(&CameraManager::dequeueLoop, this); 
}