[Qt-interest] BlockingQueuedConnection where and how to ?!

Mihail Naydenov mlists at ymail.com
Wed Dec 2 19:22:03 CET 2009


----- Original Message ----
> From: BRM <bm_witness at yahoo.com>
> To: Mihail Naydenov <mlists at ymail.com>; qt-interest at trolltech.com
> Sent: Wed, December 2, 2009 7:18:26 PM
> Subject: Re: [Qt-interest] BlockingQueuedConnection where and how to ?!
> 
> I would highly suggest you look at what the worker thread is actually receiving, 
> and I suspect you are doing something quite dangerous with your signal.
> The selection you do gets a list of pointers to items in the GUI. This is likely 
> causing your crash as operations on the GUI (add/remove/move/etc.) will change 
> the contents of the list without notifying the worker thread.
> 
> I'd highly suggest storing the actual data in a thread sharable container that 
> is linked to the GUI for display purposes only; but can be accessed by the 
> worker threads safely.
> This gives you control of how the data is added/removed/etc - and by making your 
> container a QObject derived class, you could even take advantage of 
> signals/slots for each stored item
> so worker threads could (a) use a thread sharable container to access - e.g. 
> QSharedPointer - and (b) be notified of changes in the data.
> 
> Even making your list a list of QPointers would be of benefit since that at 
> least gets notified when the pointer goes away; but you'll still need to convert 
> to a thread sharable container for the data.
> 
> $0.02
> 
> Ben
 
Thank You, for your advises, they make sense indeed. 
However, all this sending of pointers to ui elements was just for the (stupid) test, in the real project I send just a list of strings, no pointers, no ui.
Still the test should work, because I dont modify the list in any way, also the crash should be on/after modification.
Also, as I said, the "work" is fake loop returning an int, no pointers, no shared data.

Anyway, I modified the sample to send a dummy list of ints, and attaching it below. 
(the results ware exactly the same. On my 4 core machine, if I dont use blocking, it crashes within few seconds, sometimes longer - few minutes -
 every time, guaranteed!)

------------------------------------

#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 (also) avoid the crash <<<
        result = _workWatcher.resultAt(at);

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

    }

private:
    QFutureWatcher<int> _workWatcher;

};


#include "main.moc"

Q_DECLARE_METATYPE(QVector<int>)

// just because I am using Eclipse
#include <iostream>
void myMessageOutput(QtMsgType type, const char *msg)
{
    std::cout << msg << std::endl;
}

int main(int argc, char *argv[])
{
    qInstallMsgHandler(myMessageOutput);

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


      
-------------- next part --------------
A non-text attachment was scrubbed...
Name: main.cpp
Type: text/x-c
Size: 2985 bytes
Desc: not available
Url : http://lists.qt-project.org/pipermail/qt-interest-old/attachments/20091202/4a49fe5a/attachment.bin 


More information about the Qt-interest-old mailing list