Page 1 of 1

RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Posted: Thu Jun 16, 2022 6:46 am
by Filip_KONAX
I could use some help understanding multithreading in micropython (using the second core of the RP2040).
In my mainthread, running on Core 0 of the Pico, I connect to a NB-IoT modem using the hardware UART and AT commands. (I'm having some difficulties there too with processing data while receiving it, see another post.) I decided to have the second core dedicated to treating the I/O logic. For getting started using the second core, I chose the easiest task one can imagine: blink an LED, quite easy I guessed.
But: while Core 0 is doing quite some UART operations (for modem set-up and communication) and some file operations for logging purposes, I see the LED stops blinking. That shouldn't be the case with multithreading on two cores, I would guess or am I missing something fundamental?

I've put my second thread in a separate module and added a lock to exit the infinite loop.

Code: Select all

import time
import _thread
from machine import Pin
from iopins import *

def main(log, mainThreadRunningSemaphore):
    print("Starting up second Thread...")
    while mainThreadRunningSemaphore.locked():
        time.sleep(1)
        OUT_1.toggle()
        # We release the traffic light lock
        #lock.release()
    print("Exiting second Thread")
    _thread.exit()
This is how I start my second thread in my main.py:

Code: Select all

...
    mainThreadRunningSemaphore = _thread.allocate_lock()
    mainThreadRunningSemaphore.acquire()
    #startup logging
    ...
    #create communication class instance
    ...
    
     _thread.start_new_thread(secondThread.main, [log, mainThreadRunningSemaphore])
     
     #do the modem things here (infinitely)
     ...
     
     #after modem main thread stops
     mainThreadRunningSemaphore.release()
     ...
     
So, the second thread isn't running independently of the first one, is that because of the fact that the interpreter is busy?
Would there be a way to start a second micropython interpreter on the second core in order to have more independance?
Or should I switch to C instead of micropython to have better independance?
Or is this problem maybe hardware interrupt related?

Re: RP2 multithreading - Pin - UART - should I switch to C?

Posted: Thu Jun 16, 2022 9:17 am
by pythoncoder
This is a peculiar use of a lock, whose purpose is normally to control access to a shared resource. While I can't see why your code isn't working, I suggest you replace the lock with a simple shared global boolean, say stop_thread. The two threads can share variables, although care needs to be taken with complex objects like lists.

The two threads on RP2 most definitely do run concurrently. There is no shared GIL.

Re: RP2 multithreading - Pin - UART - should I switch to C?

Posted: Thu Jun 16, 2022 11:53 am
by Filip_KONAX
Hi Peter
Thank you for your reply. I've got the second thread running, not sure what I did though.
My guess is that I didn't realise the modem main thread stopped.
Because I no noticed, that not all print statements produce an output on the REPL.
I've got a logfile that continues after the print statements stopped outputting.
Any clue where to look for a reason why print has stopped?
Also breaking with Ctrl-C doesn't work anymore then.
Did I starve the REPL in some way?

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Posted: Thu Jun 16, 2022 2:46 pm
by Filip_KONAX
I think I might have found the solution for the stopping of the printing of the REPL in combination with constant uart usage.
I introduced on different locations in my code sleep_ms calls, what seels to give time to the REPL to process the printing.
Is this the way-to-go or are there better ways to cope with this problem?
If this is the way-to-go, how long should I put my script to sleep?

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Posted: Thu Jun 16, 2022 3:08 pm
by Filip_KONAX
Just upgraded to v1.19. Seems to work better.
I'll keep you posted!

Still wondering (see above) if putting sleep statements is the way-to-go...?

Re: RP2 multithreading - Pin - UART - should I switch to C?

Posted: Thu Jun 16, 2022 3:35 pm
by Filip_KONAX
pythoncoder wrote:
Thu Jun 16, 2022 9:17 am
This is a peculiar use of a lock, whose purpose is normally to control access to a shared resource. While I can't see why your code isn't working, I suggest you replace the lock with a simple shared global boolean, say stop_thread. The two threads can share variables, although care needs to be taken with complex objects like lists.

The two threads on RP2 most definitely do run concurrently. There is no shared GIL.
Hi, I don't succeed using a shared variable for stopping the second thread...
Tried using a global variable, but it doesn't seem I know how to, as the value doesn't seem to change...
Missing something, I guess. Snippet much appreciated!

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Posted: Fri Jun 17, 2022 7:50 am
by pythoncoder
Try this:

Code: Select all

import _thread
from time import sleep_ms

running = True
count = 0

def other():
    global count
    while running:
        count += 1
        sleep_ms(100)

def main():
    global running
    print("Running...")
    _thread.start_new_thread(other, ())  # Tuple of args
    while count < 100:
        print(count)
        sleep_ms(1000)
    running = False
    print(f"count when thread stopped = {count}")
    sleep_ms(2000)  # Prove that thread has stopped
    print(f"count after thread stopped for 2 secs = {count}")
As a general point, when learning a new technique I always write simple test cases like the above before tackling real applications.

Re: RP2 multithreading - Pin - UART - should I switch to C? -> changed to PRINT stops

Posted: Fri Jun 17, 2022 10:43 am
by Filip_KONAX
Hi Peter
Thank you, feeling a bit stupid. I did put the second thread in a separate module, that's why it wasn't working with a global variable. I didn't need global variable, I just needed to reference the modules namespace! :oops:
pythoncoder wrote:
Fri Jun 17, 2022 7:50 am
Try this:

Code: Select all

import _thread
from time import sleep_ms

running = True
count = 0

def other():
    global count
    while running:
        count += 1
        sleep_ms(100)

def main():
    global running
    print("Running...")
    _thread.start_new_thread(other, ())  # Tuple of args
    while count < 100:
        print(count)
        sleep_ms(1000)
    running = False
    print(f"count when thread stopped = {count}")
    sleep_ms(2000)  # Prove that thread has stopped
    print(f"count after thread stopped for 2 secs = {count}")
As a general point, when learning a new technique I always write simple test cases like the above before tackling real applications.