通过使用回调并从std :: thread或boost :: thread

时间:2018-10-13 06:35:09

标签: c++ qt

我对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。

1 个答案:

答案 0 :(得分:1)

已解决! Qt::DirectConnection是罪魁祸首,现在我使用Qt::AutoConnection,它从不会崩溃,根据文档,它是默认值:

  

(默认),如果接收器位于发出信号的线程中,   使用Qt :: DirectConnection。否则,将使用Qt :: QueuedConnection。   连接类型是在发出信号时确定的。

GM在上面的回复给了我提示(谢谢):

  

将连接类型明确指定为   Qt :: DirectConnection更改行为表明您几乎   肯定是由于穿线而竞争了

也感谢jpo38提出建议/回复。

现在我知道我说过有时候它会冻结,但不,那是不正确的,它永远不会冻结,我有些困惑。