为什么要将类的线程函数设置为静态,以便在同一个类中可以访问

Why should the thread function of a class be made static to be accessible in the same class?

本文关键字:同一个 访问 线程 函数 为什么 设置 静态      更新时间:2023-10-16

我的错误:

error: cannot convert 'MainWindow::producerThreadFunction' from type 'void* (MainWindow::)(void*)' to type 'void* (*)(void*)'
     if (pthread_create (&producer, NULL, producerThreadFunction, NULL))
                                                                      ^

头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QApplication>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <iostream>
#include <QDebug>
class MainWindow : public QMainWindow
{
    Q_OBJECT
    pthread_mutex_t mutexVariable = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t  conditionVariable = PTHREAD_COND_INITIALIZER;
    QList <int> queueLIFO;
public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();
    //  This function is run by the thread `Producer`.
    void *producerThreadFunction (void *arg);
    //  This function is run by the thread `Consumer`.
    void *consumerThreadFunction (void *arg);
    int start ();
};
#endif // MAINWINDOW_H

源文件:(发生错误的函数)

int MainWindow :: start()
{
    pthread_t producer;
    pthread_t consumer;
    if (pthread_create (&producer, NULL, producerThreadFunction, NULL))
    {
        fprintf (stderr, "Error creating thread Producern");
        return 1;
    }
if (pthread_create (&consumer, NULL, consumerThreadFunction, NULL))
{
    fprintf (stderr, "Error creating thread Consumern");
    return 1;
}
if (pthread_join (producer, NULL))
{
    fprintf (stderr, "Error joining thread Producern");
    return 2;
}
if (pthread_join (consumer, NULL))
{
    fprintf (stderr, "Error joining thread Consumern");
    return 2;
}
return 0;

}

根据这个线程,解决方案是使producerThreadFunction静态。

为什么要将类的线程函数设置为静态,以便在同一个类中可以访问?

该函数是该类的成员函数。为什么我不能直接访问它?

pthread_create需要一个函数指针,而不是指向成员函数的指针。这些在C++中是非常不同的类型,因为成员函数指针包括隐式this指针。在实践中,静态成员函数相当于非成员函数,因此可以正常工作(注意:根据标准,这在技术上是不正确的,见下文)。

如果pthread是一个C++库,它可能需要一个std::function(或者,在C++11之前,boost::function),它可以接受各种类似函数的对象;例如函数指针、成员函数指针或函子类。然而,由于pthread是一个C库,因此编写静态函数并手动传递this指针作为参数时会遇到困难。

您应该认真考虑使用std::thread(或者,在C++11之前,使用boost::thread)而不是pthreads。与在pthreads(例如std::condition_variable)中可用的同步原语相同的同步原语是可用的。std::thread构造函数可以直接接受成员函数指针:

std::thread producer(&MainWindow::producerThreadFunction, this);

标准

C和C++可以使用不同的调用约定。这意味着从C代码中调用C++函数是不安全的,除非它被封装在extern "C"块中。然而,正如StackOverflow上的这个答案所指出的,C++11 7.5/4"链接规范"说:

在确定的语言链接时忽略C语言链接类成员的名称和类成员的函数类型功能。

因此,它不能保证按标准工作。唯一符合标准的选项是将代码放入非成员函数中,该函数在内部调用成员函数:

extern "C" {
void producerThreadFunctionWrapper(void *arg)
{
    static_cast<MainWindow *>(arg)->producerThreadFunction();
}
} // extern "C"
// ...
pthread_create(&consumer, NULL, consumerThreadFunctionWrapper, this);

在实践中

在实践中,我从未遇到过静态成员函数不使用C链接的体系结构/编译器。C++FQA中对问题33.2的回答幽默地提出了同样的观点:

将静态成员视为回调问题:如果实现对C使用不同的二进制调用约定函数和C++静态成员函数,调用支持并通知他们的开发者在工作中消耗了改变思维的化学物质。

然而,值得注意的是,在StackOverflow(例如在32位Visual Studio中)上有一些关于人们被这种情况烧伤的报告。最安全的选择是使用std::thread或为回调编写extern "C"包装器。

既然2015年已经快结束了,是时候抛弃C++2003了。调用线程的最佳方式如下:

int MainWindow :: start()
{
    std::thread producer(&MainWindow::producerThreadFunction, this);
    ...

看看有多容易?而且根本不需要担心静态成员函数!