Closed tonygo closed 3 years ago
Might be related to https://github.com/micropython/micropython/issues/6899 ? ping @aivarannamaa
Might be related to micropython/micropython#6899 ?
I think it's related to this problem, indeed.
@tonygo, you may want to make the main thread wait until the background thread finishes, something like:
import _thread
thread_done = False
def work():
global thread_done
try:
... do work in secondary thread ...
finally:
thread_done = True
... do work in main thread ...
_thread.start_new_thread(work)
# Wait for the secondary thread
while not thread_done:
pass
@aivarannamaa You clearly understand this issue much better than I do. Should we add something similar to https://github.com/raspberrypi/pico-micropython-examples/blob/master/multicore/multicore.py ? Or is Tony's problem more specifically tied to his use of Thonny?
Thanks for the update. This gets rid of the error messages but sometimes mixes up the prints. One starts printing while the other is already printing. So - only print from one core and printing is VERY slow.
# Trying to understand threads
from sys import exit
import time, _thread, machine
flag = False
def task(n, delay):
global flag
led = machine.Pin(25, machine.Pin.OUT)
for i in range(n):
led.high()
time.sleep(delay)
led.low()
time.sleep(delay)
print('done')
flag = True
_thread.start_new_thread(task, (10, 0.25))
while not flag:
print("Waiting")
time.sleep(1)
I do not want waits in the code. The whole point is to do very busy things on separate cores in parallel at the same time. I want to bounce a Raspberry icon in a bounding box as fast as possible in main core and change the colour of 16 Neopixels in a ring every time the berry changes direction in the other. The Neopixel update will be pretty quick and is the 2nd core task.
I can do both separately but will probably need to lock while passing colour value.
@aivarannamaa You clearly understand this issue much better than I do. Should we add something similar to https://github.com/raspberrypi/pico-micropython-examples/blob/master/multicore/multicore.py ? Or is Tony's problem more specifically tied to his use of Thonny?
The problem may not manifest outside of Thonny, depending on how you are using it. For example, when you save your code as main.py and (soft) reboot, and you leave the REPL alone when the main thread finishes, then you don't see this problem. On the other hand, when the background thread works long enough and you are going to upload a new version of main.py via pyboard.py, you'll probably meet the same problem.
In Thonny it's becomes immediately apparent, because right after the main thread returns to the REPL, Thonny will execute a hidden command for setting up its small helpers for various management tasks (eg, querying global variables or listing files).
I do not want waits in the code. The whole point is to do very busy things on separate cores in parallel at the same time.
My suggestion does not imply sacrificing parallel processing. The idea is that when the main thread finishes before the background thread, you keep it busy and don't let it leave without its friend. Of course, you need to consider power consumption, so your version with sleep
is much better than my simplified example.
Thank you for ally your help. Initially I was concerned that an example from the Pico Makers caused error messages - not a good sign. I wonder if you know of a simple tutorial which illustrates Locking? I want to be able to use global variables but do not want a clash between cores going for the same variable at the same time.
I wonder if you know of a simple tutorial which illustrates Locking? I want to be able to use global variables but do not want a clash between cores going for the same variable at the same time.
https://micropython.org/ says "multithreading via the "_thread" module, with an optional global-interpreter-lock (still work in progress, only available on selected ports)" so I think for more detailed info you'll have to ask on the MicroPython forum.
Thanks - I did not know this topic was so close to 'the cutting-edge'.
@tonygo, here I was asking the advice for joining threads: https://forum.micropython.org/viewtopic.php?f=2&t=9705&p=54275
There seems to be locking implemented for Pico (_thread.allocate_lock
), but I don't see an elegant way to use it for joining threads (unless you are assuming that the background thread is able to get the lock before the main thread finishes, which may be the case for all practical purposes, but doesn't feel correct).
The Raspberry Pi "Getting Started" documentation indicates that MicroPython on the Pico is used through Thonny. This gave me to understand that it was the officially suggested method of running MicroPython on the Pico. https://projects.raspberrypi.org/en/projects/getting-started-with-the-pico/2
There is only one provided multicore example on the Raspberrypi Pico Micropython site: https://github.com/raspberrypi/pico-micropython-examples/blob/master/multicore/multicore.py and this generates page-fulls of errors when run via Thonny. It seems to me better to substitute an example which does work from Thonny and without generating errors.
The thread example shown below is simple, easily understood, and also does not generate any errors when run via Thonny, but it does generate an error later when stopped from Thonny. https://www.raspberrypi.org/forums/viewtopic.php?f=146&t=308150&sid=fedebc306fed95f9a029f744f37a2133#p1843844
This longer thread example does not generate any errors at all. It finishes and returns control to the Python REPL. https://www.raspberrypi.org/forums/viewtopic.php?f=146&t=301156&p=1843910#p1843910
The RP2040 MicroPython port has now been merged upstream to the main MicroPython repo, see micropython/micropython#6791, and while we're happy to support the MicroPython team with anything they need, I'd encourage you to open an issue on the MicroPython repo to ask for more example code and documentation to support the RP2040 port.
When running the example it hangs with a error box. The LED flashes correctly but the 'Done' does not get printed until the error box is cleared.
Thonny gave these error messages:
ManagementError
SCRIPT: thonny_helper.print_mgmt_value({name : (__thonny_helper.repr(value), id(value)) for (name, value) in globals().items() if not name.startswith('')})
STDOUT:
STDERR: Traceback (most recent call last): File "", line 1
SyntaxError: invalid syntax
done
I've no idea what is going on