2009-11-29 55 views
1

使用C++。我是新來的線程,這個編譯錯誤是什麼意思?

pthread_t threads[STORAGE]; // 0-99 

... 

void run() 

Error>>> int status = pthread_create(&threads[0], NULL, updateMessages, (void *) NULL); 
if (status != 0) 
{ 
    printf("pthread_create returned error code %d\n", status); 
    exit(-1); 
} 

...

void ClientHandler::updateMessages(void *) 
{ 
    string reqUpdate = "91"; // Request for update 
    string recvMSG; 
    while (true) 
    { 
     sleep(5); 
     sending(sock,reqUpdate); // send 
     recvMSG = receiving(sock); // receive 
     QString output(recvMSG); 
     emit signal_chat(output, 0); // Print message to text box 
    } 
} 

...

編譯錯誤: TCPClient.cpp:109: error: argument of type ‘void (ClientHandler::)(void*)’ does not match ‘void* (*)(void*)’

我無法弄清楚什麼是錯。 在此先感謝。

回答

7

指向成員函數的指針與具有相同簽名的全局函數不同,因爲成員函數需要其運行的附加對象。因此,指向這兩種函數的指針是不兼容的。

在這種情況下,這意味着您無法將成員函數指針傳遞給pthread_create,而只是指向非成員函數(或靜態函數)的指針。此問題的解決辦法是使用pthread_create第四參數指針傳遞給一個對象到一個全局函數,然後調用傳遞的對象的方法:

class ClientHandler { 
public: 
    void updateMessages(); 
    void run(); 
}; 

// Global function that will be the threads main function. 
// It expects a pointer to a ClientHandler object. 
extern "C" 
void *CH_updateMessages(void *ch) { 
    // Call "real" main function 
    reinterpret_cast<ClientHandler*>(ch)->updateMessages(); 
    return 0; 
} 

void ClientHandler::run() { 
    // Start thread and pass pointer to the current object 
    int status = pthread_create(&threads[0], NULL, CH_updateMessages, (void*)this); 
    ... 
} 
+0

非常感謝你^^ – 2009-11-29 22:43:01

6

這與線程無關,這是一個普通的C++錯誤,你只是傳遞一個不兼容的函數指針類型。

函數指針與成員實例函數指針不同,即使它們的簽名是相同的;這是因爲存在對這個通過的隱式引用。你無法避免這一點。

+0

所以我不能從對象中創建線程? – 2009-11-29 15:00:07

+0

您可以將updateMessages更改爲您的類的靜態函數。 然後,如果您想訪問成員數據,您可以將「this」指針作爲上下文變量傳遞給pthread_create,並且您將在updateMessages函數的第一個參數中接收該指針。 – rossoft 2009-11-29 15:23:15

+0

@rossoft是的,這將工作。 – MarkR 2009-11-29 19:19:09

0

由於在pthread_create需要一個免費的功能,創建靜態函數(是一個免費的功能)內ClientHandler的

static void Callback(void * this_pointer,int other_arg) { 
    ClientHandler* self = static_cast< ClientHandler*>(this_pointer); 
    self-> updateMessages(other_arg); 
} 
and call pthread_create as follows 

pthread_create(&threads[0], NULL, &ClientHandler::Callback, (void *) pointer_to_ClientHandler,int other_arg); 

做是因爲回調是免費的功能

+1

這在技術上是不允許的,因爲靜態成員函數的ABI是編譯器定義的(因此你不能保證)調用約定。 __If__這對你的平臺編譯器有效,你只是幸運而已。在pthreads中(因爲它是一個C庫)期望函數指針使用「C」ABI。因此,函數必須標記爲extern「C」(來自C++代碼)以保證使用正確的調用約定。 – 2009-11-29 16:04:39

+0

謝謝,但我無法刪除帖子 – yesraaj 2009-11-29 16:17:49

-1

要傳遞的,而不是一個全球性的,正常的,一個成員函數。

只要定義:

void updateMessages(void *) { 
static ClientHandler c; 
// use c.. 
} 
0

YoLinux有一個很好的並行線程的教程,我幫你在學習線程。

0

正如其他人已經說過的,問題是功能之間的簽名是不同的。類成員函數總是有一個「祕密」額外參數,this指針。所以你永遠不能傳遞一個全局函數所在的成員函數。您可以使用Boost.Bind等函數庫,或者將函數設爲類的靜態成員來解決此問題。

但最簡單,最優雅的解決方案是使用不同的線程API。

Boost.Thread是一個非常好的C++線程庫(pthreads是爲C設計的,這就是爲什麼它不能很好地與C++特性如類方法一起使用)。

我推薦使用它。

你的代碼可以改寫爲這樣的:

class ClientHandler { 
public: 
    ClientHandler(/* All the parameters you want to pass to the thread. Unlike pthreads you have complete type safety and can pass as many parameters to this constructor as you like */){...} 
    void operator()() // boost.thread calls operator() to run the thread, with no parameters. (Since all parameters were passed in the constructor and saved as member variables 
    { 
    string reqUpdate = "91"; // Request for update 
    string recvMSG; 
    while (true) 
    { 
     sleep(5); 
     sending(sock,reqUpdate); // send 
     recvMSG = receiving(sock); // receive 
     QString output(recvMSG); 
     emit signal_chat(output, 0); // Print message to text box 
    } 
    } 
    // whatever arguments you want to pass to the thread can be stored here as member variables 
}; 


boost::threead_group gr; // can store all your threads here, rather than being limited to your fixed-size array 

gr.create_thread(ClientHandler(/* construct a ClientHandler object with the parameters you like*/));