为什么要将类的线程函数设置为静态,以便在同一个类中可以访问
Why should the thread function of a class be made static to be accessible in the same class?
我的错误:
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);
...
看看有多容易?而且根本不需要担心静态成员函数!
- 通过方法访问结构
- 使用不带参数的函数访问结构元素
- 如果我只是不访问queue_front节点的子节点,而是将它们推到队列中呢?还是BFS吗
- 用于访问容器<T>数据成员的正确 API
- 访问者访问变体并返回不同类型时出错
- 尝试通过多个向量访问变量时,向量下标超出范围
- 无法访问嵌套类.类的使用无效
- cuda:多个线程访问同一个全局变量
- 两个抽象类,派生自同一个基类.如何访问从一个抽象类到另一个抽象类的指针
- 多个线程访问同一个 cuda 流
- 当 PHP、C++ 和 shell 脚本尝试访问同一个文件时,如何避免错误?
- 多个线程无法访问同一个指针而不会出错
- cv::VideoCapture:从两个线程访问同一个网络摄像头
- 两个线程(COM和WPF UI)访问同一个浮点
- 是否可以让两个c++程序访问同一个内存位置
- 为什么要将类的线程函数设置为静态,以便在同一个类中可以访问
- 同一个内核的多次启动是否可以访问共享变量?
- 如何在多线程客户机的多个线程上访问同一个套接字
- 如何从同一个类的静态函数访问类的私有成员
- 使用不同的访问模式C++将多个指针指向同一个文件