Results 1 to 11 of 11

Thread: I think, there is a problem with QNetworkReply and threads

  1. #1
    Join Date
    Apr 2006
    Posts
    31
    Thanks
    2
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default I think, there is a problem with QNetworkReply and threads

    I am using qt4.5.3 / Linux.

    It seems that QNetworkReply is not safe to be used in threads. When you compile the following code then it crashes at various different locations after a random time somewhere inside the Qt libraries.

    When I chance the code by using QObject instead of QThread as superclass (and change some calls too), this code runs fine for hours. But here with threads it crashed very soon.

    As I have investigated, there is a file qnetworkreplyimpl.cpp with the function QNetworkReplyImplPrivate::feed(const QByteArray &data) and there you find at line 377/378 the following code:
    Qt Code:
    1. char *ptr = readBuffer.reserve(data.size());
    2. memcpy(ptr, data.constData(), data.size());
    To copy to clipboard, switch view to plain text mode 
    As I have investigated, data.size() returns different sizes when called in sequence inside a thread. This seems to be caused by the low level network reads which fill the buffer and which run in some other thread, e.g the main event loop. So, the QRingBuffer readBuffer reserves some space which is given with the first call, then some other thread expands the amount of available data in QByteArray data and when memcpy gets called, it filles more data than there is prepared space. ... and there is another call to data.size() in this function.

    However, when I fix this, there are still crashes, since I am not very familiar with the code I cannot provide a real fix.


    This is all my test source, the filename is xx.cpp. The only thing you need to do is to set up a http server with a reasonable large file. Voila, it crashes ... somewhere.
    Qt Code:
    1. #include <Qt/qnetworkaccessmanager.h>
    2. #include <Qt/qnetworkreply.h>
    3. #include <Qt/qeventloop.h>
    4. #include <Qt/qapplication.h>
    5. #include <Qt/qthread.h>
    6.  
    7. class Hurz : public QThread
    8. {
    9. Q_OBJECT
    10.  
    11. public slots:
    12. void dataAvailable();
    13.  
    14. public:
    15. Hurz();
    16. void run();
    17.  
    18. private:
    19. QNetworkAccessManager *_manager;
    20. QNetworkReply *_reply;
    21. QNetworkRequest *_request;
    22. };
    23.  
    24. Hurz::Hurz()
    25. {
    26. }
    27.  
    28. void Hurz::run()
    29. {
    30. _manager = new QNetworkAccessManager();
    31.  
    32. // you need to change the url to a different one which sends you "endless" data, eg. a file with almost gigabytes of data
    33. _request = new QNetworkRequest(QUrl("http://big.server/with/extreme/large/file"));
    34. _reply = _manager->get(*_request);
    35. connect(_reply, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
    36. exec();
    37. }
    38.  
    39. void Hurz::dataAvailable()
    40. {
    41. _reply->readAll();
    42. }
    43.  
    44. int main(int argc, char **argv)
    45. {
    46. QApplication app(argc, argv);
    47.  
    48. Hurz h;
    49. h.start();
    50.  
    51. QEventLoop evLoop;
    52. for(;;)
    53. evLoop.processEvents(QEventLoop::ExcludeUserInputEvents);
    54. }
    55.  
    56. #include "xx.moc"
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Mar 2006
    Posts
    10
    Thanked 7 Times in 6 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    I think the main problem is that _reply object created in thread is accessed outside the thread (Hurtz h object lives in main thread therefore dataAvailable slot is executed in main thread).
    You can check it with QThread::currentThreadId().
    Try moveToThread

  3. #3
    Join Date
    Jul 2009
    Posts
    139
    Thanks
    13
    Thanked 59 Times in 52 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: I think, there is a problem with QNetworkReply and threads

    The creator says: (from http://labs.trolltech.com/blogs/2007...etwork-access/)
    Ankur: no, the new framework is not multi-threaded nor thread-safe, but it’s reentrant. That is, you’re allowed to use a QNeworkAccessManager only from one thread, but you can have many objects, one in each thread.
    which would seem to rule out your usage (creating in one thread, reading in another).

  4. #4
    Join Date
    Apr 2006
    Posts
    31
    Thanks
    2
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    I looked at the address returned by _reply->thread() (which is from class QObject) and it returns the same as the one returned by _manager->thread().

    Of course the address of this->thread() (this is the instance of class Hurz) is different, but that is mentioned somewhere. QThread wich is subclass of QObject ist created from the main-thread.

    However, it seems to run more stable, but crashes still, when I use
    int available = _reply->bytesAvailable();
    if(available == 0)
    return;
    _reply->read(available);
    Now the crash seems to happen elsewhere, somewhere with handling signals. There is a lot written at http://doc.trolltech.com/4.5/threads...s-and-qobjects which I still do not understand in all consequences.

    However, ths stacktrace looks now very often like this one:
    0x00002b5dc19d4356 in QNetworkReplyImplPrivate::handleNotifications (this=0x5a5250)
    at ../../include/QtCore/../../src/corelib/tools/qlist.h:416
    416 { T t = first(); removeFirst(); return t; }
    (gdb) where
    #0 0x00002b5dc19d4356 in QNetworkReplyImplPrivate::handleNotifications (this=0x5a5250)
    at ../../include/QtCore/../../src/corelib/tools/qlist.h:416
    #1 0x00002b5dc19d4479 in QNetworkReplyImpl::event (this=<value optimized out>, e=0x7697b8)
    at access/qnetworkreplyimpl.cpp:656
    #2 0x00002b5dc0cf219e in QApplicationPrivate::notify_helper (this=0x54e780, receiver=0x5963e0, e=0x602260)
    at kernel/qapplication.cpp:4065
    #3 0x00002b5dc0cf6d80 in QApplication::notify (this=0x7fffea096d00, receiver=0x5963e0, e=0x602260)
    at kernel/qapplication.cpp:3961
    #4 0x00002b5dc1767ea3 in QCoreApplication::notifyInternal (this=0x7fffea096d00, receiver=0x5963e0,
    event=0x602260) at kernel/qcoreapplication.cpp:610
    #5 0x00002b5dc1768f7d in QCoreApplicationPrivate::sendPostedEvents (receiver=0x0, event_type=0, data=0x5a3a30)
    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:213
    #6 0x00002b5dc1791903 in postEventSourceDispatch (s=<value optimized out>)
    at ../../include/QtCore/../../src/corelib/kernel/qcoreapplication.h:218
    #7 0x00002b5dc2e22ffb in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
    #8 0x00002b5dc2e2381c in ?? () from /usr/lib/libglib-2.0.so.0
    #9 0x00002b5dc2e23d2b in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
    #10 0x00002b5dc1791c8e in QEventDispatcherGlib:rocessEvents (this=0x595640, flags=<value optimized out>)
    at kernel/qeventdispatcher_glib.cpp:328
    #11 0x00002b5dc1767335 in QEventLoop:rocessEvents (this=<value optimized out>, flags=@0x40800020)
    at kernel/qeventloop.cpp:149
    #12 0x00002b5dc176759c in QEventLoop::exec (this=0x40800060, flags=@0x40800070) at kernel/qeventloop.cpp:201
    #13 0x00002b5dc1682fe8 in QThread::exec (this=<value optimized out>) at thread/qthread.cpp:487
    ...
    ######################

    Quote Originally Posted by numbat View Post
    The creator says: (from http://labs.trolltech.com/blogs/2007...etwork-access/)

    which would seem to rule out your usage (creating in one thread, reading in another).
    Sorry, english is not my native language. Am I correct or wrong?
    Last edited by Wurgl; 10th January 2010 at 13:01.

  5. #5
    Join Date
    Apr 2006
    Posts
    31
    Thanks
    2
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    However. I will drop this code totally and write my own class to access the server.

    The other side (the server) is an Intel sa1110 Chip with 206 MHz (a Mobotix webcam) and my client runs on some Opteron 244 with 1.8GHZ. The Opteron needs 100% CPU-Time just for pure reading. This is far too slow code.

    BTW: It works okay, if I create the three classes in main() and just do the retrieving in the subthread.

  6. #6
    Join Date
    Mar 2006
    Posts
    10
    Thanked 7 Times in 6 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    In first post example _reply object is read/written in h object thread (run method...) and read/written in main thread (dataAvailable slot) at same time (without synchronization. For example some pointer became invalid while still used as valid in other thread).
    The Opteron needs 100% CPU-Time just for pure reading.
    Try to wait until 100000 or more bytes arrive and then read them. The finished signal to get the last portion of bytes.
    Try (in this case Hurtz slots will be executed in Hurtz thread)
    Qt Code:
    1. Hurz::Hurz()
    2. {
    3. moveToThread(this);
    4. }
    To copy to clipboard, switch view to plain text mode 
    Some example (it crashed before using moveToThread)
    Qt Code:
    1. #include <QNetworkAccessManager>
    2. #include <QNetworkReply>
    3. #include <QCoreApplication>
    4. #include <QThread>
    5. #include <QEventLoop>
    6. #include <QDebug>
    7. #include <QTime>
    8.  
    9. class Hurz : public QThread
    10. {
    11. Q_OBJECT
    12.  
    13. public slots:
    14. void dataAvailable();
    15. void slot_finished();
    16.  
    17. public:
    18. Hurz();
    19. void run();
    20.  
    21. private:
    22. QNetworkAccessManager *_manager;
    23. QNetworkReply *_reply;
    24. QNetworkRequest *_request;
    25. QTime m_time;
    26. };
    27.  
    28. Hurz::Hurz()
    29. {
    30. moveToThread(this);
    31. m_time = QTime::currentTime();
    32. }
    33.  
    34. void Hurz::run()
    35. {
    36. qDebug() << "Hurz::run thread id is " << QThread::currentThreadId();
    37. _manager = new QNetworkAccessManager();
    38.  
    39. // you need to change the url to a different one which sends you "endless" data, eg. a file with almost gigabytes of data
    40. _request = new QNetworkRequest(QUrl("http://ftp.stack.nl/pub/users/dimitri/doxygen-1.6.2-setup.exe"));
    41. _reply = _manager->get(*_request);
    42. connect(_reply, SIGNAL(readyRead()), this, SLOT(dataAvailable()));
    43. connect(_reply, SIGNAL(finished()), this, SLOT(slot_finished()));
    44. exec();
    45. }
    46.  
    47. void Hurz::dataAvailable()
    48. {
    49. if (_reply->size() > 100000) {
    50. qDebug() << "Hurz::dataAvailable: " << "Thread id is" << QThread::currentThreadId();
    51. QByteArray arr = _reply->readAll();
    52. int ms = m_time.msecsTo(QTime::currentTime());
    53. m_time = QTime::currentTime();
    54. qDebug() << " " << arr.size() << "in" << ms << "ms. " << (float)arr.size() / 1024 / ms * 1000 << "kB/s";
    55. }
    56. }
    57.  
    58. void Hurz::slot_finished()
    59. {
    60. qDebug() << "Hurz::slot_finished: " << "Thread id is" << QThread::currentThreadId();
    61. if (_reply->size() > 0) {
    62. QByteArray arr = _reply->readAll();
    63. int ms = m_time.msecsTo(QTime::currentTime());
    64. m_time = QTime::currentTime();
    65. qDebug() << " " << arr.size() << "in" << ms << "ms. " << (float)arr.size() / 1024 / ms * 1000 << "kB/s";
    66. }
    67. quit();
    68. }
    69.  
    70. int main(int argc, char **argv)
    71. {
    72. QCoreApplication app(argc, argv);
    73.  
    74. Hurz h;
    75. //QEventLoop evLoop;
    76. QObject::connect(&h, SIGNAL(finished()), &app, SLOT(quit()));
    77. h.start();
    78.  
    79. //for(;;)
    80. // evLoop.processEvents(QEventLoop::ExcludeUserInputEvents);
    81. //evLoop.exec(QEventLoop::ExcludeUserInputEvents);
    82. app.exec();
    83. }
    84.  
    85. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 

  7. The following user says thank you to Rembobo for this useful post:

    Wurgl (12th January 2010)

  8. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: I think, there is a problem with QNetworkReply and threads

    What do you need threads here for anyway?

    By the way, I'd drop this code:
    Qt Code:
    1. QEventLoop evLoop;
    2. for(;;)
    3. evLoop.processEvents(QEventLoop::ExcludeUserInputEvents);
    To copy to clipboard, switch view to plain text mode 
    and change it to:
    Qt Code:
    1. app.exec();
    To copy to clipboard, switch view to plain text mode 
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #8
    Join Date
    Apr 2006
    Posts
    31
    Thanks
    2
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    Thanks!

    moveToThread() was the solution for both the crash and the time-eating. My selfwritten class uses about 2-3% of CPU, Qt uses about 7-8% which is okay.

    However, it seems to be a little bit strange to me, I really expected, that a subclass of QThread already lives in that thread.

  10. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: I think, there is a problem with QNetworkReply and threads

    QThread object is the thread controller, not the thread itself. And if QThread lived in the thread it represents, what would happen to it once the thread was finished?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  11. #10
    Join Date
    Jan 2008
    Location
    Poland
    Posts
    687
    Thanks
    4
    Thanked 140 Times in 132 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    Quote Originally Posted by Wurgl View Post
    However, it seems to be a little bit strange to me, I really expected, that a subclass of QThread already lives in that thread.
    Because you haven't read the Qt Documentation about QThread class :P where it is clearly written than body of run() is finally in new created thread with QThread::start() method.
    I would like to be a "Guru"

    Useful hints (try them before asking):
    1. Use Qt Assistant
    2. Search the forum

    If you haven't found solution yet then create new topic with smart question.

  12. #11
    Join Date
    Apr 2006
    Posts
    31
    Thanks
    2
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: I think, there is a problem with QNetworkReply and threads

    Quote Originally Posted by wysota View Post
    What do you need threads here for anyway?
    Reason 1: The example ist just a dummy code. The real program has multiple stages with image processing, each of these stages may be time consuming. And since I get images in an endless stream, I avoid loosing any of these images. Each stage shall run in its own thread, stage 1 is grabbing the images, stage 2 is some analysing and filtering, stage 3 is some neuronal network processing, stage 4 is storing in the file system ... and a few more stages
    Reason 2: Finally it will run on a machine with 8 cores, so why not using all of them?
    Reason 3: Because it is cool, when *ix-utility top shows a cpu-usage greater than 100% :-)

    Quote Originally Posted by wysota View Post
    QThread object is the thread controller, not the thread itself. And if QThread lived in the thread it represents, what would happen to it once the thread was finished?
    So a clean implementation is to create some subclasses of QObjects in QThread::run() which do the real work and not using moveToThread()?

Similar Threads

  1. Problem with threads
    By kvnlinux in forum Newbie
    Replies: 7
    Last Post: 21st August 2009, 17:29
  2. When to delete QNetworkReply?
    By QPlace in forum Qt Programming
    Replies: 5
    Last Post: 11th February 2009, 12:46
  3. Problem creating a QWidget using threads
    By tarod in forum Qt Programming
    Replies: 1
    Last Post: 16th November 2007, 12:45
  4. Threads problem
    By boss_bhat in forum Qt Programming
    Replies: 3
    Last Post: 2nd August 2006, 15:41
  5. Replies: 16
    Last Post: 7th March 2006, 15:57

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.