3

当我试图从另一个线程发出信号时,它会导致段错误,不知道为什么。
信号和槽都定义在同一个类中,并在主 GUI 线程下运行,但我在另一个函数中调用发出,该函数由 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. 我有一个MapGeneratorQThread现在继承的类,它连接到 ROS 并订阅一个主题。
  2. 现在我得到了另一个MyMapitem继承自QObject两者GraphicsItem的类,在这个类中我定义了一个插槽和一个信号。
  3. 现在我得到了第三个类Mainwindow,它继承自Qobject并为我设置了图形场景mymapitem
  4. 现在我要做的main是创建对象Mapgenerator并启动线程。
  5. 然后我做一个对象Mainwindow
  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);
}
4

4 回答 4

2

当您设置类时,通常涉及connect到插槽的信号,您可以选择指定连接类型

bool QObject::connect ( const QObject * sender, const char * signal,
const QObject * receiver, const char * method,
Qt::ConnectionType type = Qt::AutoConnection ) [静态]
________________ <--- 指定您的连接类型为排队的人之一

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

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

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

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

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

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

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

于 2012-07-13T20:16:05.843 回答
1

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

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

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

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

在“线程和 QObjects”中的 QT 文档中阅读更多内容

于 2012-07-13T18:34:00.393 回答
0

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

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

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

于 2012-12-20T19:41:39.973 回答
0

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

于 2012-07-13T18:56:07.863 回答