我对Qt和多线程有一个烦人的问题。下面,我创建了一些简化的代码。在我的真实代码中,原理是完全相同的,但是过于复杂,因此使用简化版本。
问题在于应用程序在运行时的不同时间点随机崩溃,并显示不同的消息:
free(): invalid pointer
double free or corruption
崩溃是从Qt内部触发的,我将在文章结尾进行解释。
这是代码的工作方式。
因此,我有 classA 启动了一个线程:
class classA
{
public:
void start();
boost::function<void (std::string)> __ptr; // for callback
private:
boost::thread * thread;
void run();
};
void classA:start()
{
thread = new boost::thread(&classA::run, this); // start the thread
}
这是在单独线程中运行的实际方法:
void classA::run()
{
for (int i = 0; i < 50000; i++)
{
static int count = 0;
__ptr("test123" + std::to_string(++count));
}
}
在我的QDialog
继承的类中,我有一个简单的方法来分配boot::function
,所以我声明了另一个boost::function
ptr。问题不在于ptr,而在于Qt,请继续阅读,回拨就可以了...
class myClassB : public QDialog
{
Q_OBJECT
public:
explicit myClassB (QWidget *parent);
classA ca;
private:
boost::function<void (std::string)> __ptr;
void mycallback(std::string);
};
在 myClassB 的构造函数中,我将这样分配回boost::function
的调用(就像我说的那样,回调工作正常)。
myClassB::myClassB()
{
this->__ptr = ( boost::bind( &myClassB::mycallback, this, _1 ) );
ca.__ptr = __ptr;
}
这是问题开始的地方。在我的classB QDialog中的回调中,我发出一个Qt信号
void myClassB::mycallback(std::string txt)
{
emit sig_qt_data_received(txt);
}
此信号在我的classB的构造函数中连接:
connect(this, SIGNAL(sig_qt_data_received(std::string)), this, SLOT(data_received(std::string)), Qt::DirectConnection);
最后是Qt插槽的实现:
void myclassB::data_received(std::string txt)
{
ui->lbl_status->setText(txt);
}
这是问题所在:
如果删除 ui->lbl_status->setText(txt);
,该程序将正常运行,永远不会崩溃;如果离开,它将随机崩溃:
free(): invalid pointer
double free or corruption
问题似乎出在Qt中,因为当我删除setText()引用时,它不会崩溃,并且我遵循了我发现的几乎每个GUI多线程过程,而我没有这样做不知道我在做什么错。
要连接Qt信号,我正在使用Qt::DirectConnection
,如果我使用Qt::AutoConnection
,它将正常工作而不会崩溃,但有时整个UI会冻结(编辑:这不正确,请参阅我的答案)。
我希望有人能提供帮助。如果您需要更多代码/真实代码,请告诉我,我将编写一个可以运行和编译的实际可运行代码,但基本原理相同,这就是代码的工作原理。
我不想使用QThread。
答案 0 :(得分:1)
已解决! Qt::DirectConnection
是罪魁祸首,现在我使用Qt::AutoConnection
,它从不会崩溃,根据文档,它是默认值:
(默认),如果接收器位于发出信号的线程中, 使用Qt :: DirectConnection。否则,将使用Qt :: QueuedConnection。 连接类型是在发出信号时确定的。
GM在上面的回复给了我提示(谢谢):
将连接类型明确指定为 Qt :: DirectConnection更改行为表明您几乎 肯定是由于穿线而竞争了
也感谢jpo38提出建议/回复。
现在我知道我说过有时候它会冻结,但不,那是不正确的,它永远不会冻结,我有些困惑。