in reply to Re: Tk and Threads
in thread Tk and Threads

Thank you for your answer. But I think I have to clarify a bit to avoid misunderstandings.

No I'm not starting the thread from a Tk callback. I know that this causes problems. The thread is started at the beginning in "thread_example.pl" with the call createMyThread().

The thread is running before Tk code is executed. I gave the thread two states: STATE_IDLE and STATE_WORK. My idea was to change the states via Events. Initially the thread is in the STATE_IDLE. So it is nothing doing as waiting.

Within the Tk callback I'm calling evWorkStart. This function is generating the event EV_WORK_START and giving data to the thread via a queue. So the state of the thread is changed from STATE_IDLE to STATE_WORK. In STATE_WORK the work function of the "ThreadWorker" is called.

When the work is done the thread is automatically changing its state to STATE_IDLE.

But the user has the possibility to press the cancel-button before the work is finished. This calls the function evWorkCancel and the event EV_WORK_CANCEL is generated. This event causes the thread to go back to the STATE_IDLE.

The problem is now that the work function is in reality very complex and has a lot of code in many modules. To achieve the goal that this work function is returning very fast I inserted function calls shallWorkBeCancelled which check if the event EV_WORK_CANCEL is there, i.e. the user pressed the cancel-button.

Because the work function is complex I had to call shallWorkBeCancelled in several modules which are called from the work-function. This is in my opinion pollution of the code.

I read the article about Tk-with-Worker-Threads. But if I understand it right it is more or less doing the same than me. It uses the shared variable thread_die.

The work-function in the Tk-with-worker-threads is very simple. So you only had to add the line if( $thread_die == 1 ){return} at one place. But if you also would have a complex function there you would have to place this line at several places. And so there would be the same pollution of code.

Please correct me If I am saying something wrong.

Your hint with the signals sound interesting. But I don't know it until now. I first have to learn about and try. And for me it is important that it is working with linux and windows. If signals only work with linux then this solution will not help me unfortunately.

Switching to gtk is also a good hint. But the problem is that I have a lot of GUI-stuff written in Tk. So if possible I want to realize the threading with Tk. But I really think about learning GTK to develop my new code with this gui-environment.

Or perhaps I'm thinking to complex. Do I really need a thread? My scenario is that the user is pressing on a start button. This shall start a function with a lot of work. I want that the user can interrupt this function at any time by pressing the cancel-button.

And I really want to say explicitly thank you to you zentara. Because nearly all my knowledge about "threads and tk" I have from posts of you which I read here in the perlmonks forum. Only with this help I was able to develop my "tk and thread solution".

Greetings,

Dirk

Replies are listed 'Best First'.
Re^3: Tk and Threads
by zentara (Cardinal) on Dec 22, 2010 at 12:35 UTC
    I read the article about Tk-with-Worker-Threads. But if I understand it right it is more or less doing the same than me. It uses the shared variable thread_die. The work-function in the Tk-with-worker-threads is very simple. So you only had to add the line if( $thread_die == 1 ){return} at one place. But if you also would have a complex function there you would have to place this line at several places. And so there would be the same pollution of code. Please correct me If I am saying something wrong.

    No, you are right on the money, and I just missed the subtle interactions in your code. I'm use to monolithic scripts. ;-)

    Your hint with the signals sound interesting. ..........Or perhaps I'm thinking to complex. Do I really need a thread? My scenario is that the user is pressing on a start button. This shall start a function with a lot of work. I want that the user can interrupt this function at any time by pressing the cancel-button

    You are right, on the same analytic path, that everyone else has followed.

    It took quite awhile to get the thread->kill signal working in the threads module. But even it, has a drawback. The docs state that a thread kill signal will not interrupt some io operations, so if you have a socket open, or some disk write hang, the thread will still not respond to the kill signal.

    So it seems you have to be very careful about wrapping things in eval statements, etc.

    There is also another problem with reusable threads, is that the memory used remains claimed by Perl, so the mem usage of a thread will be the peak mem of runs.

    There is a comprimise. It helps remove polluting code and fixes the memory use problem. Fork off the heavy work code in the threads, in a way that lets you get a pid of the process. Then stuff that pid in a thread local variable. Now, when you send a thread->kill signal to your thread,(or maybe STATE_DIE instead of signals?) in the signal callback, you can do a killfam($pid). You must be aware of the parent pid and all the children spawned, so you need killfam instead of plain kill. Read the signal(7) manpage. You can create your own custom signal.

    Or you could stick with your event_state method, and setup timers in your thread, to check for your states( as in my $thread_die variable)

    Moving to Gtk2 would be a good move, because the event looping system is much better. In Gtk2, each thread can have it's own GLib event loop.

    Imagine, a master loop, controlling many loops in other threads.

    I really want to say explicitly thank you

    Hey, I was hoping someone would come up with an object layer abstraction on top of threads, and you are doing it. Thank YOU. :-)

    But, remember one thing. Threads are only really useful when you need realtime sharing of data BETWEEN threads. If you are interested in just controlling threads, who happily run in their own space, you are better off forking, just to avoid memory gain problems, and possible non-threadsafe modules.

    Finally, from the threads perldoc:

    Correspondingly, sending a signal to a thread does not disrupt the operation the thread is currently working on: The signal will be acted upon after the current operation has completed. For instance, if the thread is stuck on an I/O call, sending it a signal will not cause the I/O call to be interrupted such that the signal is acted up immediately.

    So you cannot throw ANY code into a thread codeblock, and expect signals to work.


    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      So you cannot throw ANY code into a thread codeblock, and expect signals to work.

      But aren't those are exactly the same limitations that safe signals have outside of threads?


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        You are right, but I was just trying to point out that he cannot arbitrarily dump any code, into a thread, and expect the Cancel button to work. He can only gaurantee the Cancel button will work if he can "kill -9" some pids.

        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku ................... flash japh