当我试图从另一个线程发出信号时,它会导致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:";
}
以上是插槽定义,我只是暂时打印一条消息。
让我再详细阐述一下我的流程。
- 我有一个类
MapGenerator
,它现在继承自QThread
,它连接到ROS并订阅一个主题 - 现在我得到了另一个类
MyMapitem
,它继承自QObject
和GraphicsItem
,在这个类中我定义了一个槽和一个信号 - 现在我得到了继承自
Qobject
的第三类Mainwindow
,并为我拍摄mymapitem
设置了图形场景 - 现在我在
main
中所做的是制作Mapgenerator
的对象并启动线程 - 然后制作了一个CCD_ 11对象
- 因此,当
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,因此不能依赖于此。根据您希望连接在调用线程中的行为,明确告知连接为QueuedConnection
或BlockingQueuedConnection
(有关详细信息,请参阅链接)。
如果由于某种原因,您发现始终将连接设置为其中一种类型是不合适的,那么您也可以使用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