Threading with Python

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/02/2012 at 10:39, xxxxxxxx wrote:

I'm trying to figure out how to use threading for scripts. And having a hard time of it.

Here's my list of what I want to accomplish with threading:
1. Create a thread to run some code in it that is taxing(looping) on my system
2. Have the ability to stop the process with the ESC key by the user
3. Have this all done Asynchronously(Not sure if this is possible with scripts)

Here's a code example to get things started:

import c4d  
from c4d import threading  
  
class MyThread(threading.C4DThread) :  
    
  #Something to run and tax the system  
  def myThreadedFunction(self) :  
      for i in xrange(0,2000) :  
          mt = c4d.threading.GeIsMainThread() #Test if the main thread is running  
          print mt  
          tId = c4d.threading.GeGetCurrentThreadId()#Get the threads ID  
          print tId  
          c4d.StatusSetText(i)   
      c4d.StatusClear()    
  
def main() :  
  thread = MyThread()  
  thread.Start(c4d.THREADMODE_ASYNC, c4d.THREADPRIORITY_NORMAL)  
  thread.myThreadedFunction()  
  
if __name__=='__main__':  
  main()

This example has some problems.
-It returns "true" meaning that it's running in the main thread...Which is bad. I want another thread to be running instead.
-And I don't know how to add the ESC key to stop it from running.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/02/2012 at 11:17, xxxxxxxx wrote:

It is running in the current thread because you are calling it from the current thread. :wink: (Line 19, last line in main())
The correct version of your could would be:

import c4d  
import time  
  
class MyThread(c4d.threading.C4DThread) :  
  
  def Main(self) :  
      for i in xrange(0, 5) :  
          if self.TestBreak() :  
              print "Canceled thread-execution."  
              return  
          c4d.StatusSetText("Running since %d seconds." % i)  
          time.sleep(1)  
      c4d.StatusClear()  
  
  def TestDBreak(self) :  
      bc = c4d.BaseContainer()  
      c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ESC, bc)  
      # how to proceed?  
  
thread = MyThread()  
thread.Start()

But unfortunately I don't know how to proceed after GetInputState is called. Also, it always returns False in the Thread but does return True in the Main-thread.

@Official Support: Is this as supposed or is it a bug? The container isn't filled in another thread, only in the main-thread.

Cheers,
-Niklas

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/02/2012 at 12:22, xxxxxxxx wrote:

Originally posted by xxxxxxxx

[...]But unfortunately I don't know how to proceed after GetInputState is called. Also, it always returns False in the Thread but does return True in the Main-thread.@Official Support: Is this as supposed or is it a bug? The container isn't filled in another thread, only in the main-thread.Cheers,-Niklas

Have a look at the SDK docs ("Important threading information"). There are several things that are only allowed in the main thread - esp. GUI functionality (and therefore keyboard input), as the OS wouldn't support it otherwise.

Best regards,

Wilfried Behne

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/02/2012 at 12:55, xxxxxxxx wrote:

Can we terminate something that's running in a thread another way?
For example:Can we use a timer or something similar to stop running a script that's looping for too long?
 
I tried editing the example Nux posted to do that.
But even though I think I stopped the thread properly. It didn't stop processing the script.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/02/2012 at 13:37, xxxxxxxx wrote:

Originally posted by xxxxxxxx

Can we terminate something that's running in a thread another way?For example:Can we use a timer or something similar to stop running a script that's looping for too long? I tried editing the example Nux posted to do that.But even though I think I stopped the thread properly. It didn't stop processing the script.-ScottA

Please have a look at the C4DThread methods described in the SDK docs (e.g. End(), TestBreak(), etc.).

Best regards,

Wilfried Behne

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 12/02/2012 at 19:10, xxxxxxxx wrote:

I've been trying to understand this. But it's not making sense.
If I end a thread using End(). It does not terminate the script code from running. It looks like all that does is acts like a switch to toggle the TestBreak() function from False- to- True:

import c4d  
  
class MyThread(c4d.threading.C4DThread) :  
  
  def Main(self) :  
      i=0  
      while i<20:  
          print i  
          if self.TestBreak() : print "Thread Stopped"  #TestBreak is a Boolean "False" value until triggered "True" when the thread is stopped  
          if i>15:  
              print "Stop"       
              self.End(wait=True)                      #Triggers the thread to stop  
              #return                                  #Use this to stop the script from running any further  
          i=i+1  
  
thread = MyThread()  
thread.Start()

The only way I can see of using threads to terminate a script is by using it to control a return.
Is this correct?

Here's something else that's strange to me.
Why does this code only return the numbers between 3001-3999?
Why doesn't it print the numbers 0 - 4000?

import c4d  
  
class MyThread(c4d.threading.C4DThread) :  
  
  def Main(self) :  
      for i in xrange(0, 4000) : #Only returns the numbers 3001-3999!?  
          print i  
  
thread = MyThread()  
thread.Start()

Why it the threading forcing the print function to only return a thousand numbers?

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 01:00, xxxxxxxx wrote:

Originally posted by xxxxxxxx

I've been trying to understand this. But it's not making sense.If I end a thread using End() [...]

The main thread does:
- interaction with the GUI (drawing, keyboard input, etc.)
- Spawns treads (by calling the Start() method)
- Tells the spawned threads that they should stop (by calling the End() method for the spawned threads)

The spawned tread:
- checks via TestBreak(), if it should stop
- terminates by returning from its Main() method

Best regards,

Wilfried Behne

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 04:41, xxxxxxxx wrote:

@wbeh: But how would I then implement reactin on user-input in a thread? The documentation does even point out that you can.

_<_dt id="c4dthread.testdbreak"_>_ `>Originally posted by xxxxxxxx

C4DThread.TestDBreak`( self )

Override this to add user breaks such as pressing ESC. This function is called by TestBreak().
_="field-"=""> Return type:| bool
Returns:| True if processing should be terminated, otherwise <_<_t_>_ng>False**.

@ScottA: You must exit the thread yourself.

def Main(self) :  
  for ... :  
        if self.TestBreak() :  
          print "Quitting thread."  
          break # or return, or whatever to quit the loop and / or the function

-Niklas

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 06:17, xxxxxxxx wrote:

Originally posted by xxxxxxxx

@wbeh: But how would I then implement reactin on user-input in a thread? The documentation does even point out that you [...]

Again: You DON'T do any GUI interaction in a spawned thread. In the spawned thread you either work, react to TestBreak() or you leave the thread because your work is done.

What you can do when overriding TestDBreak is something like this:

//----------------------------------------------------------------------------------------
// Break function for the thread. A break will be signalled if the thread was requested to
// stop or if the current task takes too much time.
// Function result:          -
//----------------------------------------------------------------------------------------
Bool BackgroundThread::TestDBreak( void )
{
    if ( please_suspend )                                           // stop it?
      return( TRUE );

if ( in_action )                                                  // currently doing something?
    {
      LONG     current;
      LONG     duration;
      current = GeGetTimer();                                // this is the time when the current action started
      duration = current - action_start;
      if ( duration > 1000 )
      {
        time_out = FALSE;
      }

if (( duration / 1000 ) > MySettings::GetUserSelectableTimeout())
      {
        time_out = TRUE;
        return( TRUE );
      }
    }
    return( FALSE );
}

Best regards,

Wilfried Behne

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 08:39, xxxxxxxx wrote:

Thanks a lot guys.
I now understand that threads don't stop running scripts. But they can be used as tests to determine when to execute a return, which in turn will stop the running script.

But what's up with the strange returns I get when using a for loop inside a thread?
Why do I only get a thousand numbers from my print statement?
I don't understand why that's happening when I run a for loop inside of a thread class?

Here's another version that also only prints out a thousand numbers:

import c4d  
  
class MyThread(c4d.threading.C4DThread) :  
  
  def Main(self) :  
      for i in xrange(0, 4000) :  
          self.End()  
          self.TestBreak()  
          if self.TestBreak() :  
              print i  
  
thread = MyThread()  
thread.Start()

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 09:34, xxxxxxxx wrote:

Originally posted by xxxxxxxx

But what's up with the strange returns I get when using a for loop inside a thread?
Why do I only get a thousand numbers from my print statement?
I don't understand why that's happening when I run a for loop inside of a thread class?

The console has a buffer of one thousand lines. This is why you only get the latest thousand numbers.

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 10:47, xxxxxxxx wrote:

Not sure if I understand what that means Yannick.

The "for" loop generates print results starting from 0+ when used in the "main" thread.
But only 1000 values when used inside of a custom thread.
You say this is due to a console buffer limit. But I don't get the connection there.

I guess it really doesn't matter if I understand how the console buffer works.
I just need to know if my loops will still work the same way in threads (starting from zero+) as they work in the main thread.
Should I  just take it on faith that they work the same. Even though I can't use the print function to see the entire output values?

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 11:20, xxxxxxxx wrote:

@Scott:

Imagine you have printed exactly 1000 lines to the console.

for i in xrange(1000) :  
  print "Current:", i

If you now print another one, the first line, which contains the string Current: 0, will be erased.

Next, why are you calling C4DThread.End() within the loop? It is intended to be used outside of the thread to notify you, while looping in the main, the thread should now exit.

import c4d  
import time  
  
class MyThread(c4d.threading.C4DThread) :  
  
  def Main(self) :  
      for i in xrange(100) :  
          if self.TestBreak() :  
              print "MyThread.TestBreak() returned True, leaving the loop.."  
              break  
          print "Current:", i  
          time.sleep(1/25.)  
  
def main() :  
  thread = MyThread()  
  thread.Start()  
  time.sleep(1)  
  thread.End()  
  
main()

As expected, this code runs until frame 25 (maybe 24 or 26, that depends on the machine) and then exits because we told it to exit after we've waited for a second.

Current: 0  
Current: 1  
Current: 2  
Current: 3  
Current: 4  
Current: 5  
Current: 6  
Current: 7  
Current: 8  
Current: 9  
Current: 10  
Current: 11  
Current: 12  
Current: 13  
Current: 14  
Current: 15  
Current: 16  
Current: 17  
Current: 18  
Current: 19  
Current: 20  
Current: 21  
Current: 22  
Current: 23  
Current: 24  
Current: 25  
MyThread.TestBreak() returned True, leaving the loop..

-Niklas

PS: What is up with my posts? I see scrollbars for it, never seen that before here..

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 13/02/2012 at 12:26, xxxxxxxx wrote:

Thanks for correcting me on that Nux.
Now I see why it was returning only the last 1000 numbers the way I was using it.

Thanks to everyone for the great information in this thread... um...about threading.:joy:
Lots of good information in here.

-ScottA

On 05/10/2017 at 21:44, xxxxxxxx wrote:

Check this one...Python thread basics