我正在Ubuntu 12.10上开发一个简单的即时通讯软件,它的客户端需要GUI。
在客户端的主窗口中,我需要创建一个线程来保持从服务器收到的消息。
以下是错误消息:
main.cpp:-1: In function 'int main(int, char**)':
main.cpp:27: error: invalid conversion from 'void*' to 'void* (*)(void*)' [-fpermissive]
/usr/include/pthread.h:225: error: initializing argument 3 of 'int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)' [-fpermissive]
在maininterface.h
:
Class MainInterface: public QWidget
{
public:
explicit MainInterface(QWidget *parent = 0);
~MainInterface();
void* ServerMSGWatch(void *threadArgs=NULL); // function run in the new thread
};
maininterface.cpp
中的定义是:
void* MainInterface::ServerMSGWatch(void *threadArgs)
{
pthread_detach(pthread_self());
char arrServerMSGRecv[SERVER_MSG_MAX_SIZE + 1];
while(1){
recv(Login::sockClnt, arrServerMSGRecv, SERVER_MSG_MAX_SIZE+1, 0);
Handle_Server_MSG(arrServerMSGRecv);
memset(arrServerMSGRecv, 0, SERVER_MSG_MAX_SIZE+1);
}
return NULL;
}
main.cpp
中的:
MainInterface mWindow;
mWindow.show();
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, mWindow.ServerMSGWatch(), NULL);
在这个question中,我发现使用C ++编译器编译c代码可能有问题。
所以我尝试添加'c_pthread.h':
#ifndef C_PTHREAD_H
#define C_PTHREAD_H
#ifdef __cplusplus
extern "C" {
#endif
void* ServerMSGWatch(void *threadArgs=NULL);
void Handle_Server_MSG(char *arrServerMSGRecv);
#ifdef __cplusplus
}
#endif
#endif // C_PTHREAD_H
和c_pthread.cpp
:
void* ServerMSGWatch(void *threadArgs=NULL)
{
//definition
}
void Handle_Server_MSG(char *arrServerMSGRecv)
{
//definition
}
然后在main.cpp
中调用它:
#include "c_pthread.h"
pthread_t pthreadID;
pthread_create(&pthreadID, NULL, ServerMSGWatch(), NULL);
但我仍然遇到同样的错误。
答案 0 :(得分:5)
你有两个问题:第一个是你调用函数而不是传递它。另一个是更微妙的,并且你不能使用非静态类成员函数作为线程函数。
最后一个问题的原因是因为非静态成员函数有一个隐藏的第一个参数,即this
指针。
在这种情况下,您可以通过添加static
成员函数来解决它,并将指向对象的指针作为参数传递给线程函数。然后静态函数调用对象中的实际函数:
class MainInterface: public QWidget
{
public:
...
static void* StaticServerMSGWatch(void* arg)
{
reinterpret_cast<MainInterface*>(arg)->ServerMSGWatch();
return nullptr;
}
void ServerMSGWatch(); // function run in the new thread
};
...
pthread_create(&pthreadID, NULL, &MainInterface::StaticServerMSGWatch, &mWindow);
如果您有支持C ++ 11的编译器和库,则可以改为使用std::thread
:
std::thread myThread(&MainInterface::ServerMSGWatch, &mWindow);
如您所见,您不再需要静态成员函数。
答案 1 :(得分:4)
您使用的是Qt,因此我强烈建议您使用QThread
。这将保证兼容性,并且与您程序的其余部分的互操作将更好。
话虽如此,您需要将函数指针传递给pthread_create
,并且成员函数指针不是函数指针:要么使它成为static
,要么使其成为独立函数。
答案 2 :(得分:1)
在C ++ 11中,没有必要使用低级系统库:
std::thread thread([&]{mWindow.ServerMSGWatch();});
如果你坚持使用C ++的历史版本,那么,既然你说你正在使用Qt,你可以考虑它的线程类QThread
。
如果你坚持使用pthread,那么作为一个C API,它对成员函数一无所知,所以你需要一个非成员函数或静态成员函数。 (严格来说,你应该只使用一个声明为extern "C"
的非成员函数,但实际上C ++函数可以用于任何合理的实现。)
所以你需要一个包装函数来调用成员函数:
void * CallServerMSGWatch(void * p) {
return static_cast<MainInterface*>(p)->ServerMSGWatch();
}
告诉pthread_create
将适当的指针传递给:
pthread_create(&pthreadID, NULL, CallServerMSGWatch, &mWindow);
答案 3 :(得分:0)
mWindow.ServerMSGWatch()是一个函数调用。
mWindow.ServerMSGWatch是一个函数指针。