3
votes

When I am trying to emit a signal from another thread it causes a segfault, not sure why.
Both the signal and slot are defined in the same class and running under the main GUI thread, but I call the emit in another function which is being controlled by a boost thread type of thread.

I am using Qt4 and Ubuntu 10.04 is my OS. This function is called from another thread which is emitting the signal.

    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 );



}

Here above is my constructor of Qt class.

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

And above is the slot definition I am just printing a message for the time being.

Let me elaborate my flow a little bit more.

  1. I have one class MapGenerator which is inherited from QThread now, which is connected to ROS and subscribing to a topic.
  2. Now I get another class MyMapitem which is inherited from QObject and GraphicsItem both and in this class I have defined a slot and a signal.
  3. Now I got a third class Mainwindow which is inherited from Qobject and setting up the graphicsscene for me taking mymapitem.
  4. Now what I do in main is to make object of Mapgenerator and start the thread.
  5. Then I make an object of Mainwindow.
  6. So when Mapgenerator thread starts it subscribes data from ROS and calls a function in MyMapItem and transfer data there.

Here I want to emit a signal so I know that new data arrived. Then I update the item which is already in the scene there in the Mainwindow constructor. The connection is made in MyMapItem class constructor.

Thanks Here i post my main method where i am creating the thread and main window.

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();
}

here in Main window constructor i made Mapitem object

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 Answers

2
votes

When you are setting up the class, which often involves connecting signals to slots, you have the option to specify a connection type.

bool QObject::connect ( const QObject * sender, const char * signal,
const QObject * receiver, const char * method,
Qt::ConnectionType type = Qt::AutoConnection ) [static]
________________ <--- specify your connection type as one of the queued ones

The default value, Qt::AutoConnection relies on QThread stuff to know if the signal is coming from the same thread or a different one. Since you're not using QThreads, you can't rely on this. Explicitly tell the connection to be made as QueuedConnection or BlockingQueuedConnection depending on how you want it to behave in the calling thread (see the link for details).

If for some reason you find it inappropriate to set the connection to one of these types all the time, you can also utilize QMetaObject::invokeMethod to call in from a different thread. Notice that this function also allows you to specify a connection type:

Invokes the member (a signal or a slot name) on the object obj. Returns true if the member could be invoked. Returns false if there is no such member or the parameters did not match. The invocation can be either synchronous or asynchronous, depending on type:

If type is Qt::DirectConnection, the member will be invoked immediately.

If type is Qt::QueuedConnection, a QEvent will be sent and the member is invoked as soon as the application enters the main event loop.

If type is Qt::BlockingQueuedConnection, the method will be invoked in the same way as for Qt::QueuedConnection, except that the current thread will block until the event is delivered. Using this connection type to communicate between objects in the same thread will lead to deadlocks.

If type is Qt::AutoConnection, the member is invoked synchronously if obj lives in the same thread as the caller; otherwise it will invoke the member asynchronously.

1
votes

is being controlled by a boost thread type of thread.

QT's signals are implemented in QObject which is aware of all kinds of metadata about the QObjects associated with QT's signals and slots. One of these pieces of metadata is the QThread associated with the slot's QObject which dictates the default behavior of how the slot is called for a signal (ie in the same thread, posted to a different QThread, etc).

Its doubtful that this will work well with other threading libraries such as boost's. Its pretty certain that QObject when connecting the signal/slot won't even know that the slot's QObject is even associated with a second thread. It will probably erroneously be associated with the main QThread of your application.

Associating objects with threads is a prominent feature of QT compared to other threading APIs. Its very unlikely that QT will be able to automatically know that you are creating threads with another library and be able to make it sensically associate threads with QObjects in a way that QT understands threads, signals, and slots in a way that can make them threadsafe.

Read more in the QT docs in "Threads and QObjects"

0
votes

You have to use a blocking queued signal. Qt has this functionality in QThreads where you define your connection with Qt::BlockingQueuedConnection. I don't know about boost threads.

0
votes

I have experienced the same problem recently. I have quite a few calls of shell command via subprocess from dependent GUI threads that are working just fine, but one just refuses to work correctly and segfaults. The difference I have came to is exactly in the fact that I'm trying to run it from the main GUI thread and it was segfaulting when i was trying to emit a signal that was usually emitted from subthread!

My solution to avoid segfaulting was to move the part of dialog that required some shell involvement to a separate QThread, effectively inheriting the same common class that other threads in my app are using. The problem is gone! QThread is the key!

see full answer here: https://stackoverflow.com/a/13978817/673423