[Qt-interest] BlockingQueuedConnection... or QtConcurrent BUG ?!

Mihail Naydenov mlists at ymail.com
Sat Dec 12 17:44:39 CET 2009


Some time ago I send a mail " BlockingQueuedConnection where and how to ?! "
about a crash that is avoided by using BlockingQueuedConnection signal-slot.
I also added a test code that uses QtConcurrent to spawn the background threads the ui is trying to communicate with (through signals and slots).

I recently encountered the issues again (in a different scenario), but this time, using QtCreator, I managed to get 
a stacktrace of the error (Eclipse failed at that the first time). So I decided to run my old test in QtCreator/Debug 

Here is the result:

SIGSEGV

0    QVector<int>::at    qvector.h    323    0x00414c27    
1    QtConcurrent::ResultIterator<int>::pointer    qtconcurrentresultstore.h    117    0x0041491a    
2    QtConcurrent::ResultIterator<int>::value    qtconcurrentresultstore.h    111    0x004148d9    
3    QFutureInterface<int>::resultReference    qfutureinterface.h    250    0x00414acb    
4    QFuture<int>::resultAt    qfuture.h    182    0x00414bc4    
5    QFutureWatcher<int>::resultAt    qfuturewatcher.h    132    0x004149e7    
6    worker::workdoneAt    main.cpp    133    0x00411f17    
7    worker::qt_metacall    main.moc    145    0x0040161a    
8    QMetaObject::metacall    qmetaobject.cpp    237    0x6a200e14    
9    QMetaCallEvent::placeMetaCall    qobject.cpp    574    0x6a20b0cf    
10    QObject::event    qobject.cpp    1252    0x6a20d0f2    
11    QApplicationPrivate::notify_helper    qapplication.cpp    4242    0x00c32252    
12    QApplication::notify    qapplication.cpp    3661    0x00c2fdb7    
13    QCoreApplication::notifyInternal    qcoreapplication.cpp    704    0x6a1fc512    
14    QCoreApplication::sendEvent    qcoreapplication.h    215    0x6a2604a4    
15    QCoreApplicationPrivate::sendPostedEvents    qcoreapplication.cpp    1345    0x6a1fd5a3    
16    qt_internal_proc    qeventdispatcher_win.cpp    507    0x6a21ea87    
17    USER32!IsWindowVisible    C:\Windows\system32\user32.dll    0    0x759486ef    
18    ??        0    0x00080680    
19    ??        0    0x00000401    
20    ??        0    0x00000000    
...    <More>                

Although the crash can be avoided throgh blocked connection, the real problem seams to be indeed in QtConcurrent after all! 

Running my real code, I noticed the crash rises when the concurrent job is restarted (this is also true for this test app)... now
considering the stacktrace, Im pretty convinced there some sort of race condition or something, 
accessing the result from the QFuture variable and setting/starting a newjpb through QtConcurrent::mapped(...) call.
As I said the crash before is also avoided when not getting the result from the job.

Again, here is the test code. 
I might be wrong what causes it, but please test it and enlighten me.

thank you
MihaiNaydenov
----------------------------
#include <QtGui>

// lame work doing function

int work(int item)
{

    int timespend = qrand();

    int result = 0;
    for(int i=0; i < timespend*2; i++)
        result = i;

    return result;
}

class view : public QListWidget
{
    Q_OBJECT
public:
    view(QWidget* parent=0) : QListWidget(parent)
    {
        connect(this, SIGNAL(itemSelectionChanged()), SLOT(onitemSelectionChanged()));


        for(int i=0; i < 1000; i++)
        {
            insertItem(i, new QListWidgetItem("item_" + QString::number(i)));
        }

        startTimer(0);
    }

    void timerEvent (QTimerEvent* e)
    {

        clearSelection();
        killTimer(e->timerId());

        // select randomly some items

        QItemSelection selection;

        int rowL = qrand();
        int max = model()->rowCount() - 1;
        if(max < 0)
            max = 0;

        while (rowL > max )
        {
            rowL = qrand();
        }
        int rowR = qrand();
        while (rowR > max )
        {
            rowR = qrand();
        }

        if(rowR > rowL)
            qSwap(rowR, rowL);

        selection.select(model()->index(rowR, 0),  model()->index(rowL, 0));

        selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect);


        // every 0 to 1500 ms we will submit another job

        int timeout = qrand();
        while (timeout > 1500 )
        {
            timeout = qrand();
        }

        startTimer(timeout);

    }

signals:
    void needWorkdone(const QVector<int>& items);

private slots:

    void onitemSelectionChanged ()
    {
        QVector<int> dummy(selectedItems().count());

        emit needWorkdone(dummy);
    }

};


// a worker (living in another thread)

class worker : public QObject
{
    Q_OBJECT

public:
    worker(QObject* parent=0)
    {
        // for simplicity the work result is handled in the worker

        connect(&_workWatcher, SIGNAL(resultReadyAt(int)), SLOT(workdoneAt(int)));
    }

    ~worker() { _workWatcher.cancel(), _workWatcher.waitForFinished(); }

public slots:
    void dowork(const QVector<int>& items)
    {
        if(!items.isEmpty())
        {
            if(_workWatcher.isRunning())
            {
                _workWatcher.cancel();
                _workWatcher.waitForFinished();
            }

            qDebug()<<"work on";
            _workWatcher.setFuture(QtConcurrent::mapped(items, work));
        }
    }

    void workdoneAt(int at)
    {
        qDebug()<<"ready at"<<at;

        int result = 0;

        // >>> commenting this line will avoid the crash <<<
        result = _workWatcher.resultAt(at);

        qDebug()<<"result: "<<result;

    }

private:
    QFutureWatcher<int> _workWatcher;

};


#include "main.moc"

Q_DECLARE_METATYPE(QVector<int>)


int main(int argc, char *argv[])
{
    qRegisterMetaType< QVector<int> >();

    QApplication a(argc, argv);

    QThread th;
    th.connect(&a, SIGNAL(aboutToQuit()), SLOT(quit()));

    worker w;
    w.moveToThread(&th);

    th.start();

    view v;

    w.connect(&v, SIGNAL(needWorkdone(const QVector<int>&)), SLOT(dowork(const QVector<int>&))
              //, Qt::BlockingQueuedConnection // uncommnet to avoid the crash, but block the ui.
              );

    v.show();

    return a.exec();
}


      



More information about the Qt-interest-old mailing list