Skip to content

thread_example_1

Boris Lovosevic edited this page Jan 27, 2018 · 3 revisions

Thread examples

1. Creating threads, notifications, locking ...


Two threads will be created, performing simple arithmetic operations.
Both threads will use the same function, but with different arguments.

First, we need to import the needed modules and create the thread function:

import machine, time, _thread

# Both threads will use the same function
def th_func(tmr):
    x = 0
    f = 1.1
    ntf = 0
    tm = 0
    n = 100000
    start_time = 0
    end_time = 0
    myname = _thread.getSelfName()
    # Init the thread timer
    t = machine.Timer(tmr)
    t.init(mode=t.CHRONO)
    while True:
        ntf = _thread.wait()
        if ntf == _thread.EXIT:
            # Terminate the thread
            return
        elif ntf > 0 and ntf < 5:
            # Start the instruction loop
            if (ntf == 2) or (ntf == 4):
                # For commands 2 and 4
                # Lock the thread, other threads will not execute
                _thread.lock()
            # Get start time and start the timer
            start_time = time.ticks_us()
            t.start()
            if ntf < 3:
                # For commands 1 and 2 run integer addition test
                for i in range(0, n):
                    x += 1
            else:
                # For commands 3 and 4 run float multiplication test
                for i in range(0, n):
                    f *= 1.2345
            # Stop the timer and get the end time
            t.stop()
            end_time = time.ticks_us()
            if (ntf == 2) or (ntf == 4):
                # Unlock the thread, other threads can now run
                _thread.unlock()
            # Get the elapsed time
            tm = t.value()
        elif ntf == 7:
            # Print the operation summary
            print("[{}] Elapsed: {} us ({:.3f} us inst time) , start: {}, end: {}".format(myname, tm, tm/n, start_time, end_time))
            tm = 0
            start_time = 0
            end_time = 0

At start, the thread function initializes some local variables and creates a timer for measuring the elapsed times.
The timer used is determined from the function argument.
After the initialization, the function executes the infinite loop.
_thread.wait() is executed which puts the thread into waiting state for infinite time. During the wait, the function uses no resources.
When a notification is received, the function continues the execution and check the notification value:

  • if _thread.EXIT notification is received, the function returns, terminating the thread
  • if notification 7 is received, the results from the last command are printed.
  • if notifications 1 - 4 are received, they are interpreted as commands
    • 1 & 2 execute 100000 integer additions and measure the execution time
    • 3 & 4 execute 100000 float multiplications and measure the execution time
    • for commands 2 & 4 lock the thread (prevent other threads from running) while executing the command loop

Start the threads and list the the running threads:

>>> th1 = _thread.start_new_thread("THRD#1", th_func, (1,))                                                                                 
>>> th2 = _thread.start_new_thread("THRD#2", th_func, (2,))                                                                                 
>>>                                                                                                                                         
>>> _thread.list()                                                                                                                          
ID=1073586276, Name: THRD#2, State: waiting, Stack=4096, MaxUsed=948, Type: PYTHON                                                          
ID=1073581228, Name: THRD#1, State: waiting, Stack=4096, MaxUsed=956, Type: PYTHON                                                          
ID=1073447944, Name: MainThread, State: running, Stack=20480, MaxUsed=2616, Type: MAIN                                                      

Request single thread to run the addition test:

_thread.notify(th1, 1)
True                                                                                                                                        
#wait some time
time.sleep_ms(1000)
#request the result
_thread.notify(th1, 7)
True                                                                                                                                        
>>> [THRD#1] Elapsed: 334714 us (3.347 us inst time) , start: 92310422, end: 92645235                                                       

The execution time was ~33.5 ms.


Now, request both thread to run the addition test, both thread will run simultaneously:
(Using 0 as thread ID argument in _thread.notify() will send the notification to all running threads. )

>>> _thread.notify(0, 1)
True                                                                                                                                        
#wait some time
time.sleep_ms(1000)
#request the result
_thread.notify(0, 7)
True                                                                                                                                        
>>>
[THRD#2] Elapsed: 685324 us (6.853 us inst time) , start: 2970786146, end: 2971471567                                                   
[THRD#1] Elapsed: 683008 us (6.830 us inst time) , start: 2970786357, end: 2971469397                                                       

As expected, the elapsed time is approximately double than for a single thread (~68.4 ms) and both threads started the command at approximately the same time.


Now, request both thread to run the addition test, but request that the thread locks during the calculation loop:

>>> _thread.notify(0, 2)
True                                                                                                                                        
#wait some time
time.sleep_ms(1000)
#request the result
_thread.notify(0, 7)
True                                                                                                                                        
>>>
>>>
[THRD#2] Elapsed: 284342 us (2.843 us inst time) , start: 3737026856, end: 3737311298                                                   
[THRD#1] Elapsed: 284279 us (2.843 us inst time) , start: 3737311489, end: 3737595798                                                       

We can see that the total execution time and calculation time are somewhat lower (~56.9 / ~28.4 ms) than with both thread running simultaneously due to fact that the main thread was blocked during the calculation loop in both threads.
Note that the th2 has started first, blocked during the calculation, then th1 started when th2 unblocked.


The similar tests can be run with float multiplication:

>>> _thread.notify(0, 4)                                                                                                                    
True                                                                                                                                        
>>> _thread.notify(0, 7)                                                                                                                    
True                                                                                                                                        
>>>
[THRD#2] Elapsed: 574453 us (5.745 us inst time) , start: 4390469846, end: 4391044408                                                   
[THRD#1] Elapsed: 641261 us (6.413 us inst time) , start: 4391044554, end: 4391685956                                                       
                                                                                                                                            
>>> _thread.notify(0, 3)                                                                                                                    
True                                                                                                                                        
>>> _thread.notify(0, 7)                                                                                                                    
True                                                                                                                                        
>>>
[THRD#2] Elapsed: 1348498 us (13.485 us inst time) , start: 4420614908, end: 4421963510                                                 
[THRD#1] Elapsed: 1317523 us (13.175 us inst time) , start: 4420615437, end: 4421933080