Discussion about "Threads, Events and QObjects" article



  • Since the wiki apparently doesn't support Discussion pages yet, I'm starting this thread to collect feedbacks about a (long) article I've written on the wiki these days about Threads and Events in Qt. The article itself is here: http://developer.qt.nokia.com/wiki/ThreadsEventsQObjects

    Any comment, review or contribution is very welcome!



  • [quote author="Gerolf Reinwardt" date="1292312695"]Hi Peppe,

    As I can't send you emails via the system, I try to give some feedback to the article this way:
    [/quote]

    I think "private messages" were somehow disabled, hope I've enabled them now...

    [quote]
    First of all: Congratulations, a very good article. I also thought about writing something about this, but now you have :-))
    [/quote]

    Thank you so much :)

    [quote]
    I just have some small extensions / add-ons:

    • In the chapter Events and the event loop you state, events are always asynchronous, thats true, if you don't send them via QCoreApplication::sendEvent(...)
      [/quote]

    That's true, but I don't know how to bring that in. All in all, the article (as of now!) is not an in-depth review of Qt's event system; along with sendEvent, many many things are missing (event filters, QCoreApplication::notify, how to create and send custom events, etc...)

    [quote]

    • Please mare a bigger warning on using QCoreApplication::processEvents(). I saw many applications crashing, because they used it and were surprised that the quit was executed although they are currently processing some events. And that happened esecially if tsendPostedEvents was called in a library...
      [/quote]

    What do you mean? Right now there's a simple example by an hypotetic recursion into a slot. Do you think I should stressing on it even more?

    [quote]

    • Regrading the dialogs, they spin a local event loop :-)
      [/quote]

    I know, in fact there's a note there.

    [quote]

    • Threads and Objects:
      ** please state that the thread afinity depends on the running thread, that creates the object. If I create an object inside the QThread constructor, it depends on the creator's thread. Often seen problems here :-)
      [/quote]

    Good point. Will do.

    [quote]
    ** you could add that QObject::moveToThread() is a push, not a poll, which could make it a bit clearer, what is meant by "... we must use it from the thread the object is living in...". Some of my colleges understood push and poll better..
    [/quote]

    Good point again; the Qt docs use a good lexicon :)



  • bq. What do you mean? Right now there’s a simple example by an hypotetic recursion into a slot. Do you think I should stressing on it even more?

    I meant that it can not only fore recursion, it can also fore a stutdown or delete of an object, that you currently work on. Think of deleteLater, which is executed by the event loop. This can happen when you call @QApplication::processEvents@. And then, perhaps, an object, where yiou think it exists, is away. And I saw suxgh tghings, especially not recursions but unexpected object deletion which result in a crash. And then all you get is:
    bq. It crashes, I don't know why, but here the memory is freed.....

    And you are the happy person to find the bug, they introduced by spinning the event loop out of scope...

    So I would make a bigger note with many exclamation marks and warnings... :-))



  • moving this to Wiki forum, thats the right place to initiate discussions on wiki articles



  • [quote author="Gerolf Reinwardt" date="1292356379"]bq. What do you mean? Right now there’s a simple example by an hypotetic recursion into a slot. Do you think I should stressing on it even more?

    I meant that it can not only fore recursion, it can also fore a stutdown or delete of an object, that you currently work on. Think of deleteLater, which is executed by the event loop. This can happen when you call @QApplication::processEvents@. And then, perhaps, an object, where yiou think it exists, is away. And I saw suxgh tghings, especially not recursions but unexpected object deletion which result in a crash. And then all you get is:
    bq. It crashes, I don't know why, but here the memory is freed.....

    And you are the happy person to find the bug, they introduced by spinning the event loop out of scope...

    So I would make a bigger note with many exclamation marks and warnings... :-))[/quote]

    Ok, I got it now :-)

    Well, I've integrated your suggestions here and there. Give it a read if you want to :)

    [quote author="chetankjain" date="1292393650"]moving this to Wiki forum, thats the right place to initiate discussions on wiki articles[/quote]

    Ops! You're right, sorry about that.



  • Hi,
    thanks again, the article is really good, and I think, the pitfalls are clearer now. So looking fporward to your next article :-))



  • bq. how to start, stop, join a thread under (at least) one major operating system;

    Is joining threads such a common pattern?
    I've always imagined threads as autonomous agents. This I was able to produce programmatically and at some point they were finished and forgotten. Whether or not the program code orphaned never seemed to matter to me.



  • Joining threads is common, if you put parts of a bigger thing to threads to do that in paralell and want to wait for all results being finished. I know, it can also be done with QtConcurrent but some programs are older than QtConcurrent :-))



  • [quote author="Wolf P." date="1292845577"]bq. how to start, stop, join a thread under (at least) one major operating system;

    Is joining threads such a common pattern?
    I've always imagined threads as autonomous agents. This I was able to produce programmatically and at some point they were finished and forgotten. Whether or not the program code orphaned never seemed to matter to me.[/quote]

    It's a pattern, that's all. For instance, a possible use case is telling a worker thread to finish, then actually wait for it to end (by joining it), then deallocate some resources used by it.



  • Gerolf, I see. The somewhat outdated framework I worked with, provided only the forking.
    Do you know a good real-world example?

    Peppe, as I see, to join means simply to wait?



  • Join means wait for finish, yes.
    I have some in my work, but they are not open source :-)
    removing objects, which are are internally multithreadded for example. You have to close all threads before removing the object.



  • [quote author="Wolf P." date="1292847084"]Gerolf, I see. The somewhat outdated framework I worked with, provided only the forking.
    Do you know a good real-world example?

    Peppe, as I see, to join means simply to wait?[/quote]

    I was pretty sure it was standard lexicon when it comes to threading: it means "block the calling thread until the target thread terminates"; and yes, it's what QThread::wait() does. See for instance:
    http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_join.3.html
    http://download.oracle.com/javase/6/docs/api/java/lang/Thread.html#join()
    http://perldoc.perl.org/threads.html#DESCRIPTION

    Now that you're telling me, perhaps should I change that term?



  • I must admit, I did not read the wiki article, but have some experience with QThread. The term "join a thread" was unknown to me, so although this might be a common term in threading in general, it seems it is not used in Qt world.



  • It is common in Boost threadding for example, that's where I know it from. If it is a general term... ???



  • I can put a footnote and/or a link there, just in case. The point is that you should know what QThread::wait() is for. What do you think?



  • Knowledge about QThread::wait() is definitely needed.

    maybe this wording is a bit more clear:

    "how to start, stop, wait for a thread (aka join a thread in boost and others) under (at least) one major operating system"



  • [quote author="Volker" date="1292850647"] "how to start, stop, wait for a thread [/quote]
    This sounds very familiar to me (FYI: Win32/VCL).



  • Ok, I changed the sentence to
    [quote]
    how to start and stop a thread, and wait for it to finish, under (at least) one major operating system;
    [/quote]

    Thank you all for your feedback :)



  • Another choice of terminology has me confused: reentrant. Thread-safe I understood, but the definition of reentrancy seemed not clearly demarcated from it. Maybe a slight reworking of the text could help for a better understanding of the difference.



  • Sorry for this naive comment. Finally I found that this is Qt terminology: http://doc.qt.nokia.com/latest/threads-reentrancy.html



  • It is not just Qt terminology. It's general programming terminology and something everyone who does at least the slightest bit of multi-threading should know about.

    http://en.wikipedia.org/wiki/Reentrant_(subroutine)
    http://en.wikipedia.org/wiki/Thread_safety



  • [quote author="Franzk" date="1292858262"]...and something everyone who does at least the slightest bit of multi-threading should know about.[/quote] thx for the WP references :)

    BTW: I did some multithreaded coding without problems, and without thinking about reentrance.



  • To be honest, the little problem is that there might be some confusion due to literature and/or other toolkits. That's why I specified that in the article I follow the Qt conventions; anyway, I added a link to http://doc.qt.nokia.com/latest/threads-reentrancy.html, just to make it even more clear :-)



  • It's good. The basics are the same across libraries though (bad library if it diverges...).



  • After reading "Reentrancy and Thread-Safety":http://doc.qt.nokia.com/latest/threads-reentrancy.html , I think the term reentrance is not the best choice, because re-entering (in a sense of entering it twice) isn't really possible. (My problem seems to be that I'm familiar with the non-reentrance of MS-DOS.)

    Classes that can be safely used by different threads at different times, I would name just safe. To be honest, I would not discuss it at all, but rather mark those that cannot be used from different threads at different times, maybe as "tread-local" or so.

    Am I completely wrong here?



  • Hi Wolf,
    Thread-local is normally used for members/memory. So there is the "ThreadLocalStorage":http://en.wikipedia.org/wiki/Thread-local_storage for example. "Reentrant":http://en.wikipedia.org/wiki/Reentrant_(subroutine) and "thread-safety":http://en.wikipedia.org/wiki/Thread_safety are general terms (from my understanding) which are widely used. So I would stay with the used terms.



  • [quote author="Wolf P." date="1292922748"]
    Classes that can be safely used by different threads at different times, I would name just safe. To be honest, I would not discuss it at all, but rather mark those that cannot be used from different threads at different times, maybe as "tread-local" or so.

    Am I completely wrong here?[/quote]

    There are three possible cases:

    • Classes/methods/objects/functions/data structures which (...whose instances) can be used at the same time from multiple threads, without the need of serializing cuncurrent accesses. That's what thread-safe means.
    • Classes/methods/objects/functions/data structures which (...whose instances) cannot be used at the same time from multiple threads, therefore all accesses must be externally serialized. That's what reentrant means. Notice that
      ** Thread-safe implies reentrant
      ** Taking a reentrant class and forcibly serializing all possible accesses with a mutex makes it thread-safe
    • Classes/methods/objects/functions/data structures which (...whose instances) cannot be used from multiple threads at all. There isn't a specific name for this case (we usually say "not thread-safe nor reentrant"). For instance, QWidget and all of its subclasses are usable only from the main thread.


  • Ok. The term reentrant (in the given context) is now clear to me.

    But please note the following example: when you call the Win32 function SendMessage (sending to another process) and get reply-blocked, your process can be re-entered by SendMessage calls from other processes. So, for me, reentrance (in general) has also something to do with recursion.



  • I added a toc to the page. (and to the "wiki syntax help":http://developer.qt.nokia.com/wiki/WikiSyntax too)



  • Unfortunately, the term "reentrancy" is not really clearly defined in computer world.

    Michael Suess complains in his "blog entry:"http://www.thinkingparallel.com/2007/06/08/the-most-overused-word-in-parallel-programming-reentrancy/ about the situation. Reading the comments, it seems that there are at least two definitions of reentrancy in the context of single threading (regarding recursive function calls) and in the context of multi threading. This may confuse the people with a single threading background (DOS!) when heading over to multithreaded programming.

    Anyways, the definitions are out in the wild and as long as we are in Qt context, we should use the terms defined by the Trolls to avoid further confusion. Otherwise we would need another round of BabelFishing for these kinds of things, but I doubt there's any T-Shirts to win :-)



  • [quote author="Volker" date="1292932902"]but I doubt there's any T-Shirts to win :-)[/quote]Huh, imagine T-shirts stating something about your re-entrancy...



  • [quote author="Franzk" date="1292935405"][quote author="Volker" date="1292932902"]but I doubt there's any T-Shirts to win :-)[/quote]Huh, imagine T-shirts stating something about your re-entrancy...
    [/quote]

    What a about

    "I'm a male - I'm not thread safe!"

    [Edit - ok, a bit offtopic now :-) Volker]



  • "I am NOT re-entrant"



  • Qt also requires that all objects living in a thread are deleted before the QThread object that represents the thread is destroyed; this can be easily done by creating all the objects living in that thread on the QThread::run() method’s stack.

    Do you mean that
    this can be easily done by deleting all the objects living in that thread on the QThread::run() method’s stack.
    ?



  • Object created on the stack of QThread::run() should get destroyed automatically, when it goes out of scope.



  • [quote author="changsheng230" date="1293679684"]Qt also requires that all objects living in a thread are deleted before the QThread object that represents the thread is destroyed; this can be easily done by creating all the objects living in that thread on the QThread::run() method’s stack.

    Do you mean that
    this can be easily done by deleting all the objects living in that thread on the QThread::run() method’s stack.
    ?[/quote]

    No: I mean that if you do
    @
    MyThread::run()
    {
    Object obj1, obj2, obj3;
    OtherObject foo, bar;
    /* ... */
    }
    @

    All those objects will:

    • be created on run()'s stack;
    • be living in the "MyThread" thread;
    • get automatically destroyed immediately before run() returns (thus, terminating the thread).


  • Remember that instance will be a dangling pointer after run() returns. One solution
    would be the use of smartpointer.

    @
    MyThread::run()
    {
    Class* instance = new Class;
    /* ... */
    }
    @



  • Another solution would be, to create objects as children of objects that will be destoyed. (But choose objects for parentship that reside in the same thread.)



  • There seem to be two copies of this article now. This one: https://developer.qt.nokia.com/wiki/Threads_Events_QObjects has a revision history going back to Pepe's original post on 10 Dec through Alexandra's name change on 10 Feb. This one: https://developer.qt.nokia.com/wiki/ThreadsEventsQObjects was posted by Volker on 23 Feb under the old name. Based on a quick doc compare, I think the content of the two are identical except for the title.

    @Volker: are there other changes in your 23 Feb edit that I'm not seeing? I'd like to consolidate the two back to the (new) name.



  • The two articles are identical. My "version" (that without the underscores) is only a link to the actual article. The reason is, that the old version of the link is referred in some other articles and in a blog entry.

    Unfortunately it does not redirect to the actual article but pulls in its content and it does not leave a message of doing so.


Log in to reply
 

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