2

Brief explanation of what I'm working with: There are 3 boards that need to communicate over serial.

  1. BB AI
  2. Nucleo STM32 L4XX (A)
  3. Nucleo STM32 L4XX (B)

Now the BB AI works as a hub connecting both 2 Nucleo boards together using a python script. The serial communication is handled by using pyserial (in the python script that resides in the BB AI).

Nucleo A handles solenoid valves via commands that are sent over serial from the BB AI (input() function to get users commands) and nucleo B reads sensor values which the requirement is to read sensor values 20 times per second.

Needed: Run two functions that handle nucleo A and nucleo B from the BB AI using threads since the task is more IO bound than CPU bound.

Problem: The function_A that handles nucleo A from the BB AI is needed to get the sensor values that function_B gives 20 times every seconds.

At the same time function_A needs to read user input using:

while True:
       user_in = input("> ")

So far I can get the function_B values from Nucleo B in function_A for Nucleo A (using threading).

Running threading like:

with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
    f1 = executor.submit(function_A)
    f2 = executor.submit(function_B)

and in function_B the while loop that reads user input:

while True:
    #before sending values to Nucleo A try to print them
    #to check they can run concurrently as users input commands.
    #both is a global variable from function_B
    print(both , end='\r' , flush=True)

    # get user commands and service
    user_in = input("> ")
    user_in = user_in.lower()
    comand_check(user_in)

Is there a way to print without stopping and use input() function too?

1 Answers1

2

You will want to have a dedicated thread processing input(). It looks like you already have two threads for two input()s. Great!

Now they need to talk to each other while avoiding any race condition. A message queue works well as it handles locking for you.

Note that input() blocks the thread until an answer is ready. Nothing else can happen on this thread while blocked, and when it is not blocked it should quickly process whatever input it just received and then promptly jump back into being blocked in input().

This Non-blocking, multi-threaded example answer might help you implement what you are looking for.

How to Break from input()

The classic approach to tell a thread to die is to set a flag then rely on that thread checking that flag in a timely fashion. Press CTRL-C aka ^C to break out of input:

stop = False
While not stop:
    try:
        a = input()
        queue.add(a)
    except KeyboardInterrupt:
        stop = True
Razzle Shazl
  • 1,287
  • 1
  • 8
  • 20
  • There is non-blocking IO but that would necessitate not using `input()`. It also adds a lot of complexity. Just mentioning it for thoroughness. – Razzle Shazl Mar 04 '21 at 07:54
  • is there any way to use queue between 3 threads that contain while True loops ??? 1 - the input() while True loop , 2- while True loop that generates values and 3- while True loop that prints the data(I want to get both values from 2 while True loops and print them I was hoping I could use queue) – Yusme Pradera Martinez Mar 04 '21 at 20:25
  • I again assert that you should really consider to have one dedicated thread per `input()` unless you have some reason and I can't think of a good one. The complexity it adds is not that much, and quite straightforward. If you want to interleave behaviour of a single thread between `input()` and work, that's totally fine. Just make sure you are not starving either `input()` or the work. As for queues, have 1 queue between 2 threads per each direction. So double that if you need 2 ways. – Razzle Shazl Mar 06 '21 at 02:15
  • 1
    I added the dedicated input() thread and everything works as I wanted !!! THANK YOU so much!!!! – Yusme Pradera Martinez Mar 06 '21 at 03:57
  • if I wanted to kill all threads and finish the python script as soon as the user types exit how could I stop all threads and finish the program???? .I returned used f1.cancel() and f2.cancel but the script dosnt finishes???? – Yusme Pradera Martinez Mar 06 '21 at 04:16
  • @YusmePraderaMartinez Appended to answer a way to kill your threads – Razzle Shazl Mar 06 '21 at 06:01
  • Razzle what if you didn't wanted to use cntrl+c and use an user command. For example is the user types "exit". Is there no ways to kill the thread pool executor with an user input?????? Or your work around also works for an user inputting "stop" – Yusme Pradera Martinez Mar 06 '21 at 08:55
  • @YusmePraderaMartinez yes you could have a magic word 'stop'. Use `if a == 'stop': stop = True`. In fact, since you have a simple loop, you could use `break` and do away with the `stop` flag. Also I looked at [`input`](https://docs.python.org/3/library/functions.html#input) and documentation does not seem to have a configuration for aborting. – Razzle Shazl Mar 06 '21 at 17:05
  • how do I accept you answer as a solution? New to stack overflow – Yusme Pradera Martinez Mar 06 '21 at 22:24
  • @YusmePraderaMartinez Hey I'm glad that this answer was useful to you. Looks like this answer is already picked as the accepted answer by OP (you). The green checkmark signifies the answer that is accepted by OP. – Razzle Shazl Mar 06 '21 at 22:49
  • In terms of safely ending the thread pool executor though is there an efficient way to do it? I looked on Google but nothing that explains how if you want to kill a thread the force the thread pool executor to kill all threads that are also running in a while True loop.For example I have setup the input() to brake when "stop" but the other two threads that are producing they are still running , is it good practice to queue.get and check in all the threads that are running and then break or is there a way to stop all the threads when one gets the stop word? – Yusme Pradera Martinez Mar 06 '21 at 23:20
  • @YusmePraderaMartinez I am unsure about what you mean by *efficient way*. What I have shown is industry practice. If you have another question feel free to create a new one. Comments aren't really for discussion. – Razzle Shazl Mar 07 '21 at 01:25