2009-11-29 59 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*/));