【问题标题】:Create a new thread using C in Qt4.8在 Qt4.8 中使用 C 创建一个新线程
【发布时间】:2013-12-05 10:36:56
【问题描述】:

我正在 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); 

但我仍然遇到同样的错误。


PS:对一些不当之处表示抱歉。

【问题讨论】:

  • 您使用 C 而不是 C++ 有什么原因吗?另外,由于您使用的是 Qt,请尝试使用 Qthreads 而不是 pthreads。

标签: c++ c linux qt pthreads


【解决方案1】:

你有两个问题:第一个是你调用函数而不是传递它。另一个更微妙的是,你不能将非静态类成员函数用作线程函数。

最后一个问题的原因是因为非静态成员函数有一个隐藏的第一个参数,即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 - 哦,是的 - 甚至没有注意到“mWindow”。一旦我看到了 ()。
【解决方案2】:

您正在使用 Qt,因此我强烈建议您使用 QThread。这将保证兼容性,并且与程序其余部分的互操作性会更好。

话虽如此,您需要将函数指针传递给pthread_create,而成员函数指针不是函数指针:要么将其设为static,要么将其设为独立函数。

【讨论】:

    【解决方案3】:

    在 C++11 中,无需使用低级系统库:

    std::thread thread([&]{mWindow.ServerMSGWatch();});
    

    如果您坚持使用 C++ 的历史版本,既然您说您使用的是 Qt,那么您可能会考虑它的线程类 QThread

    如果你被 pthreads 困住了,作为一个 C API,它对成员函数一无所知,所以你需要一个非成员或静态成员函数。 (严格来说,您应该只使用声明为 extern "C" 的非成员函数,但实际上 C++ 函数适用于任何合理的实现)。

    所以你需要一个包装函数来调用成员函数:

    void * CallServerMSGWatch(void * p) {
        return static_cast<MainInterface*>(p)->ServerMSGWatch();
    }
    

    并告诉pthread_create 将合适的指针传递给此:

    pthread_create(&pthreadID, NULL, CallServerMSGWatch, &mWindow); 
    

    【讨论】:

      【解决方案4】:

      mWindow.ServerMSGWatch() 是一个函数调用。

      mWindow.ServerMSGWatch 是一个函数指针。

      【讨论】:

      • 不,&amp;mWindow.ServerMSGWatch 是一个成员函数指针。 mWindow.ServerMSGWatch 不是有效的完整表达式。
      猜你喜欢
      • 1970-01-01
      • 2014-01-27
      • 2013-07-19
      • 2013-08-28
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多