当我尝试从另一个线程发出信号时,会导致段错误,不确定原因 信号和槽都在同一个类中定义并在主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:";
}
以上是插槽定义我暂时只打印一条消息。
让我详细说明一下我的流程。
MapGenerator
,它现在继承自QThread
,它连接到ROS并订阅一个主题。 MyMapitem
和QObject
的课程GraphicsItem
,在这个课程中我定义了一个插槽和一个信号。 Mainwindow
,该课程继承自Qobject
并为mymapitem
设置了iconsscene。 main
做的是创建Mapgenerator
的对象并启动线程。 Mainwindow
的对象。 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);
}
答案 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,因此您不能依赖此。明确告诉连接为QueuedConnection
或BlockingQueuedConnection
,具体取决于您希望它在调用线程中的行为方式(有关详细信息,请参阅链接)。
如果由于某种原因您发现不一定要将连接设置为这些类型之一,您还可以使用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理解线程,信号和插槽的方式使线程,信号和插槽能够使线程安全
中的QT文档中阅读更多内容答案 2 :(得分:0)
您必须使用阻塞排队信号。 Qt在QThreads中具有此功能,您可以使用Qt :: BlockingQueuedConnection定义连接。我不知道提升线程。
答案 3 :(得分:0)
我最近遇到过同样的问题。我从相关的GUI线程通过子进程调用了很多shell命令,它们正常工作,但是只是拒绝正常工作和段错误。我遇到的不同之处在于我正在尝试从主GUI线程运行它,当我试图发出通常从子线程发出的信号时它就是segfaulting!
我避免segfaulting的解决方案是将需要一些shell参与的对话框部分移动到单独的QThread,有效地继承了我的应用程序中其他线程正在使用的相同公共类。问题消失了! QThread是关键!
请在此处查看完整答案:https://stackoverflow.com/a/13978817/673423