从Qt中的其他线程发出信号时出现分段故障



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

我使用的是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. 现在我得到了另一个类MyMapitem,它继承自QObjectGraphicsItem,在这个类中我定义了一个槽和一个信号
  3. 现在我得到了继承自Qobject的第三类Mainwindow,并为我拍摄mymapitem设置了图形场景
  4. 现在我在main中所做的是制作Mapgenerator的对象并启动线程
  5. 然后制作了一个CCD_ 11对象
  6. 因此,当Mapgenerator线程启动时,它从ROS订阅数据,并调用MyMapItem中的一个函数并在那里传输数据

在这里,我想发出一个信号,这样我就知道新的数据到达了。然后我在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);
}

在设置该类时,通常需要向插槽发送connect信号,您可以选择指定连接类型。

bool QObject::connect(const QObject*sender,const char*signal,
const QObject*接收器,const char*方法,
Qt::ConnectionType type=Qt:(自动连接)[static]
________________<---将您的连接类型指定为排队的之一

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

如果由于某种原因,您发现始终将连接设置为其中一种类型是不合适的,那么您也可以使用QMetaObject::invokeMethod从不同的线程进行调用。请注意,此函数还允许您指定连接类型:

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

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

如果类型是Qt::QueuedConnection,则将发送一个QEvent,并且成员是在应用程序进入主事件循环时立即调用。

如果类型是Qt::BlockingQueuedConnection,则该方法将在与Qt::QueuedConnection相同,只是当前线程将阻止,直到事件被传递。使用此连接类型同一线程中的对象之间的通信将导致死锁。

如果类型为Qt::AutoConnection,则如果obj与调用者生活在同一个线程中;否则它将调用成员异步。

正由提升线程类型的线程控制。

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

这与boost等其他线程库是否能很好地配合使用是值得怀疑的。可以肯定的是,当连接信号/插槽时,QObject甚至不知道插槽的QObject与第二个线程相关联。它可能会错误地与应用程序的主QThread相关联。

与其他线程API相比,将对象与线程关联是QT的一个突出功能。QT不太可能自动知道您正在使用另一个库创建线程,并能够以QT理解线程、信号和插槽的方式使线程与QObject有意义地关联,从而使它们具有线程安全性。

在"线程和QObjects"中的QT文档中阅读更多信息

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

我最近遇到了同样的问题。我从依赖的GUI线程通过子进程调用了不少shell命令,这些线程运行得很好,但其中一个线程拒绝正常工作,并出现segfault。我遇到的不同之处在于,我正试图从主GUI线程运行它,而当我试图发出通常从子线程发出的信号时,它是分段错误的!

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

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

相关内容

  • 没有找到相关文章

最新更新