Getting QList from Another Thread



  • Hi,

    I'm a bit confused as to how I'm supposed to used invokeMethod, which I understand is the best way to exchange data across threads if I don't want to use a signal/slot. However, I keep getting a memory access violation.

    Am I doing this the right way, or am I missing something?

    This is the method I'm using to get data from my other object, ClassTwo
    @void ClassOne::lookAtSomeStuff()
    {
    QList<QUrl>* list;
    QMetaObject::invokeMethod(myClassTwoObject, "getStuff", Qt::DirectConnection, Q_RETURN_ARG(QList<QUrl>*, list));
    QList<QUrl>::const_iterator i = list->begin();
    for (i; i != list->end(); ++i)
    {
    QUrl url = QUrl((*i).url()); //this is the line that throws the exception
    doSomething(url);
    }
    }@

    And here is my ClassTwo, which runs in a separate thread:

    @QList<QUrl>* ClassTwo::getStuff() {
    return this->myStuff;
    }@

    I can confirm that the object in ClassTwo is not null (actually has ~20 items). Am I missing something really obvious?


  • Moderators

    Would be a bit easier to use foreach here:
    @
    foreach (QUrl url, list) {
    doSomething(url);
    }
    @

    Try invoking the method with Qt::QueuedConnection. In general, you are passing a pointer, which means that both threads gain access to the same part of the memory (and very probably that is why you are getting that error - OS is not allowing your main thread access to memory of thread2. But I'm not too fluent in threading, might be wrong). If your list is not heavy, I would recommend passing by value, not by pointer - you'll avoid a lot of potential caveats.


  • Moderators

    Why would you want to run getStuff in another thread when your first thread is expected to block till the other thread is done?

    Usually you pass some data to a worker object and connects one of the worker object's signals to some slot. Then you have the worker run in the second thread while the first one continues to update the UI. Once the signal is emitted by the worker object the slot that it is connected to will retrieve the data.

    You can get pretty far without locking here: When you set the data there is only the UI thread accessing the worker (it is not running after all), while the worker is processing the data the UI will leave the data alone and once the worker is done the UI thread can freely access the data again.



  • Tobias, the way I have it set up is that the main thread is sending a small piece of data to the ClassTwo thread. The ClassTwo thread then does a long analysis of the data, and I want to be able to get access to the result. I could use the slot method, but I was just curious as to what was causing the issue with that snippet.

    sierdzio, I think you may be right that the OS doesn't want my main thread accessing memory that is part of the second thread. I'll try passing by value and see how that works.


  • Moderators

    The OS cares about processes, not threads. So it is fine with threads meddling with each others memory.

    You did not initialize your pointer to 0, so checking it to be non-zero will most likely work out, even if invokeMethod fails. Did you check the return value of invokeMethod?



  • I tried setting it to a QueuedConnection like sierdzio suggested, but it spits back an error that I can't used a QueuedConnection with a return value.

    InvokeMethod is returning true.

    In the debugger, if I open up the list variable, the value for "d" is <Memory access error>


  • Moderators

    Of course it does. You never initialize the list pointer, so accessing it after invokeMethod has failed on you is going to get you a crash.

    As I said before: This whole code makes absolutely no sense at all. You can not use return values in multithreaded programming. In your approach you have thread A, calling getStuff, which is supposed to be run in thread B (with DirectConnection it is not, even if invokeMethod would work). A will then block, wait for B to finish and return the result.

    So in effect you have A blocked the whole time you are processing data in B. Great! You just added threading overhead to your application and still have a UI that blocks all the time.

    Read up on multithreaded programming... there is Qt Concurrent for offloading heavy processing tasks to worker threads. That may or may not match your need. There are also "QFuture":http://qt-project.org/doc/qt-4.8/qfuture.html , which is basically a promise to deliver a result at some point in the future to help get around this problem as well (not that it will help here, where you require the result right away).


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.