Дождитесь завершения потоков, прежде чем запускать их снова

#python #multithreading #raspberry-pi #python-multithreading

#python #многопоточность #малина-пи #python -многопоточность

Вопрос:

Я создаю программу, которая управляет 2 двигателями через Raspberry Pi. Я запускаю код на Python, и мне интересно, как добиться следующего :

  • Запустите motor1
  • Запустите двигатель 2 одновременно
  • Дождитесь завершения работы обоих двигателей
  • Запустите motor1
  • Запустите двигатель 2 одновременно
  • и т.д.

    То, что я сделал до сих пор, — это создание потока и использование очереди.

     class Stepper(Thread):
    
        def __init__(self, stepper):
            Thread.__init__(self)
            self.stepper = stepper    
            self.q = Queue(maxsize=0)
    
        def setPosition(self, pos):
            self.q.put(pos)
    
        def run(self):
            while not self.q.empty():
                item = self.q.get()
                // run motor and do some stuff 
    
    thread_1 = Stepper(myStepper1)
    thread_2 = Stepper(myStepper2)
    thread_1.start()
    thread_2.start()
    
    loop = 10
    while(loop):
        thread_1.setPosition(10)
        thread_2.setPosition(30)
        # I want to wait here
        thread_1.setPosition(10)
        thread_2.setPosition(30)
        loop = loop - 1
    
        thread_1.join()
        thread_2.join()
     

И thread_1, и thread_2 не завершатся одновременно в зависимости от количества шагов, которые необходимо обработать двигателю.
Я пытался использовать функциональность Lock(), но я не уверен, как правильно ее реализовать. Я также думал о воссоздании потоков, но не уверен, что это правильное решение.

Комментарии:

1. Пожалуйста, исправьте ваши отступы, это мешает, когда другой читает ваш код.

2. Где вы удаляете предметы из себя. вопрос и где вы его инициализируете, например q = Queue()

3. Да, очередь инициализируется в инициализации def следующим образом: self . q = Queue(maxsize=0) (каждый поток имеет свою собственную очередь); Я также делаю item = self.q.get() в моем методе run(), я обновлю свой код.

Ответ №1:

Вы можете использовать Semaphore на самом деле:

 from threading import Semaphore

class Stepper(Thread):

    def __init__(self, stepper, semaphore):
        Thread.__init__(self)
        self.stepper = stepper
        self.semaphore = semaphore

    def setPosition(self, pos):
        self.q.put(pos)

    def run(self):
        while not self.q.empty():
            try:
                # run motor and do some stuff
            finally:
                self.semaphore.release()  # release semaphore when finished one cycle

semaphore = Semaphore(2)
thread_1 = Stepper(myStepper1, semaphore)
thread_2 = Stepper(myStepper2, semaphore)
thread_1.start()
thread_2.start()

loop = 10
for i in range(loop):
    semaphore.acquire()
    semaphore.acquire()
    thread_1.setPosition(10)
    thread_2.setPosition(30)
    semaphore.acquire()
    semaphore.acquire()  # wait until the 2 threads both released the semaphore
    thread_1.setPosition(10)
    thread_2.setPosition(30)
 

Комментарии:

1. Некоторые try finallys идеально подошли бы здесь, чтобы убедиться, что замок снят.

2. @rocksteady верно.

3. Спасибо, я пытаюсь с помощью семафора, но я сталкиваюсь с проблемами: — Кажется, что когда я запускаю () поток, потому что очередь пуста, поток останавливается и больше никогда не запускается. (например, если я вызову self.run() в setPosition(), потоки больше не будут выполняться одновременно) — я могу добавить while(True) в метод run , но тогда поток никогда не остановится, а программа никогда не завершится.

Ответ №2:

Вы можете использовать метод thread join следующим образом:

 thread_1.join() # Wait for thread_1 to finish
thread_2.join() # Same for thread_2
 

Согласно документации по адресу https://docs.python.org/3/library/threading.html#threading .Поток.соединение:

Поток может редактироваться join() много раз.

Чтобы запускать потоки повторно, вам нужно будет повторно инициализировать Thread объект после каждого запуска.

Комментарии:

1. Я не уверен, как «повторно инициализировать объект потока после каждого запуска». Это просто thread_1 = Stepper(myStepper1) в моем while(цикл)? Я не уверен, что это лучшее решение, но опять же я новичок в коде Python.