在Qt中从其他线程发出信号时出现分段错误

时间:2012-07-13 18:31:44

标签: multithreading qt segmentation-fault signals-slots

当我尝试从另一个线程发出信号时,会导致段错误,不确定原因 信号和槽都在同一个类中定义并在主GUI线程下运行,但是我在另一个函数中调用emit,这个函数由boost线程类型的线程控制。

我使用的是Qt4,Ubuntu 10.04是我的操作系统。 从另一个发出信号的线程调用此函数。

    void MyMapItem::updateMap(std::vector<int> data11)
{
my_mutex.lock();    
cout<< "i am in updatemap"<<endl;
data12.clear();
data12=data11;
cout<<"size of data"<<data12.size()<<endl;
my_mutex.unlock();
emit mera_signal();
}

    MyMapItem::MyMapItem(QGraphicsItem *parent )
{

    QObject::connect(this,SIGNAL(mera_signal()),this,SLOT(mera_slot()),Qt::BlockingQueuedConnection );



}

以上是我的Qt类的构造函数。

void MyMapItem::mera_slot()
{
cout<< "signal is emitted"<<endl;
qDebug() << "Date:";
} 

以上是插槽定义我暂时只打印一条消息。

让我详细说明一下我的流程。

  1. 我有一个类MapGenerator,它现在继承自QThread,它连接到ROS并订阅一个主题。
  2. 现在我得到另一个继承自MyMapitemQObject的课程GraphicsItem,在这个课程中我定义了一个插槽和一个信号。
  3. 现在我得到了第三个课程Mainwindow,该课程继承自Qobject并为mymapitem设置了iconsscene。
  4. 现在我在main做的是创建Mapgenerator的对象并启动线程。
  5. 然后我创建一个Mainwindow的对象。
  6. 因此,当Mapgenerator线程启动时,它会从ROS订阅数据并调用MyMapItem中的函数并在那里传输数据。
  7. 这里我想发出一个信号,所以我知道新的数据到了。然后我在Mainwindow构造函数中更新已存在于场景中的项目。连接在MyMapItem类构造函数中进行。

    由于 在这里,我发布我的主要方法,我在创建线程和主窗口。

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        ros::init(argc,argv,"last");
        MapGenerator::MapGenerator mg(argc,argv);
        //boost::thread ros_thread(boost::bind(&MapGenerator::init2, &mg));
        mg.start(); // Qthread 
        MainWindow w(argc,argv);
        w.show();
        return a.exec();
    }
    

    这里在主窗口构造函数中我创建了Mapitem对象

    MainWindow::MainWindow( int argc, char **argv, QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        this->setWindowTitle("My app");
        mapitem = new MyMapItem();
        scene = new QGraphicsScene(0,0,4000,4000);
        ui->graphicsView->setScene(scene);
        scene->addItem(mapitem);
    }
    

4 个答案:

答案 0 :(得分:2)

当您设置通常涉及connect信号到插槽的课程时,您可以选择指定connection type

  

bool QObject :: connect(const QObject * sender,const char * signal,
  const QObject *接收器,const char *方法,
  Qt :: ConnectionType type = Qt :: AutoConnection)[静态]
  ________________&lt; ---将您的连接类型指定为排队的

之一

默认值Qt::AutoConnection依赖于QThread内容来了解​​信号是来自同一个线程还是来自不同的线程。由于您没有使用QThreads,因此您不能依赖此。明确告诉连接为QueuedConnectionBlockingQueuedConnection,具体取决于您希望它在调用线程中的行为方式(有关详细信息,请参阅链接)。

如果由于某种原因您发现不一定要将连接设置为这些类型之一,您还可以使用QMetaObject::invokeMethod从其他线程调用。请注意,此功能还允许您指定连接类型:

  

在对象obj上调用成员(信号或插槽名称)。   如果可以调用该成员,则返回true。如果有,则返回false   没有这样的成员或参数不匹配。调用可以是   同步或异步,具体取决于类型:

     

如果类型是   Qt :: DirectConnection,会立即调用该成员。

     

如果输入   是Qt :: QueuedConnection,将发送一个QEvent,成员是   应用程序进入主事件循环后立即调用。

     

如果输入   是Qt :: BlockingQueuedConnection,该方法将在中调用   与Qt :: QueuedConnection相同,但当前线程除外   将阻止直到事件发送。使用此连接类型   同一线程中的对象之间的通信将导致死锁。

     

如果type是Qt :: AutoConnection,则会同步调用该成员   obj与调用者生活在同一个线程中;否则会调用   该成员是异步的。

答案 1 :(得分:1)

  

由boost线程类型的线程控制。

QT的信号在QObject中实现,QObject知道与QT信号和时隙相关的QObject的各种元数据。其中一个元数据是与插槽的QObject相关联的QThread,它指示了如何为信号调用插槽的默认行为(即在同一个线程中,发布到不同的QThread等)。

令人怀疑的是,这可以与其他线程库(如boost)一起使用。很可靠的是,QObject在连接信号/插槽时甚至不知道插槽的QObject甚至与第二个线程相关联。它可能会错误地与您的应用程序的主要QThread相关联。

将对象与线程相关联是QT与其他线程API相比的一个突出特点。 QT能够自动知道您正在使用另一个库创建线程,并能够以一种QT理解线程,信号和插槽的方式使线程,信号和插槽能够使线程安全

"Threads and QObjects"

中的QT文档中阅读更多内容

答案 2 :(得分:0)

您必须使用阻塞排队信号。 Qt在QThreads中具有此功能,您可以使用Qt :: BlockingQueuedConnection定义连接。我不知道提升线程。

答案 3 :(得分:0)

我最近遇到过同样的问题。我从相关的GUI线程通过子进程调用了很多shell命令,它们正常工作,但是只是拒绝正常工作和段错误。我遇到的不同之处在于我正在尝试从主GUI线程运行它,当我试图发出通常从子线程发出的信号时它就是segfaulting!

我避免segfaulting的解决方案是将需要一些shell参与的对话框部分移动到单独的QThread,有效地继承了我的应用程序中其他线程正在使用的相同公共类。问题消失了! QThread是关键!

请在此处查看完整答案:https://stackoverflow.com/a/13978817/673423