Потоковый класс Python вызывает другой поточный класс (помощь в очереди) - PullRequest
0 голосов
/ 02 октября 2018

Я пытаюсь управлять 3-осевым принтером с помощью контроллера x-box.Чтобы получить входные данные из x-box, я позаимствовал код у martinohanlon https://github.com/martinohanlon/XboxController/blob/master/XboxController.py. Я также создал код, который читает текстовый файл построчно (G-код) для перемещения принтера.

Я хотел бы иметь возможность использовать контроллер X-Box, чтобы выбрать файл G-кода и запустить его, а затем, пока принтер работает, продолжать прислушиваться к кнопке отмены только в случае, если печать идет неправильно,Контроллер - это многопоточный класс, а мой readGcode - это многопоточный класс.

Проблема, с которой я сталкиваюсь, заключается в том, что когда я использую контроллер для запуска класса readGcode, я не могу связаться с контроллером, пока этот поток не закончится.

Мое временное решение - использовать контроллер для выбора файла, а затем передать путь этих файлов в класс readGcode.В классе readGcode он продолжает пытаться открыть файл, используя блок try, и терпит неудачу, пока путь к файлу не будет приемлемым.Затем он изменяет bool, который пропускает дальнейшее чтение до тех пор, пока это не будет сделано.

Код:

import V2_Controller as Controller
import V2_ReadFile as Read
import time
import sys
# file daialogue
import tkinter as tk
from tkinter import filedialog

# when X is selected on the x-box controller 
def X(xValue):
    if not bool(xValue):
        try:
            f=selectfile()
            rf.setfilename(f)
        except:
            print("failed to select file")

def selectfile():
    try:
        root = tk.Tk()  # opens tkinter
        root.withdraw()  # closes the tkinter window
        return filedialog.askopenfilename()
    except Exception:
        print("no file")

# setup xbox controller
xboxCont = Controller.XboxController(controlCallBack, deadzone=30, 
scale=100, invertYAxis=True)
# init the readfile class
rf = Read.Readfile()

# set the custom function for pressing X
xboxCont.setupControlCallback(xboxCont.XboxControls.X, X)

try:
    # start the controller and readfile threads
    xboxCont.start()
    rf.start()

    xboxCont.join()
    rf.join()

    while True:
        time.sleep(1)

# Ctrl C
except KeyboardInterrupt:
    print("User cancelled")

# error
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise

finally:
    # stop the controller
    xboxCont.stop()
    rf.stop()

V2_Readfile

# Main class for reading the script
class Readfile(threading.Thread):

    # supports all variables needed to read a script
    class readfile:
        fileselect = True
        linecount = 0
        currentline = 0
        commands = []

    # setup readfile class
    def __init__(self):
        # setup threading
        threading.Thread.__init__(self)
        # persist values
        self.running = False
        self.reading = False

    def setfilename(self,filename):
        self.filename = filename

    # called by the thread
    def run(self):
        self._start()

    # start reading
    def _start(self):
        self.running = True
        while self.running:
            time.sleep(1)
            if not self.reading:
                try:
                    self.startread()
                except:
                    pass

    def startread(self):
        try:
            with open(self.filename, "r") as f:  # read a local file
                f1 = f.readlines()
                # run through each line and extract the command from each line
                linecount = 0
                line = []
                for x in f1:
                    # read each line into an array
                    line.append(x.split(";")[0])
                    linecount += 1

                # Store the variables for later use
                self.readfile.linecount = linecount
                self.readfile.commands = line
                self.reading = True
        except Exception:
            pass

        i = 0
        while i < self.readfile.linecount and self.reading:
            self.readfile.currentline = i + 1
            self.readline(i)
            i += 1

        # the following stops the code from reading again
        self.reading = False
        self.filename = ""


    def readline(self,line):
        Sort.sortline(self.readfile.commands[line])

    # stops the controller
    def stop(self):
        self.running = False

1 Ответ

0 голосов
/ 02 октября 2018

Вы можете использовать примитив синхронизации, например threading.Event .

. Для этого вам нужно изменить класс Readfile следующим образом:

from threading import Event


class Readfile(threading.Thread):

    # setup readfile class
    def __init__(self):
        # setup threading
        threading.Thread.__init__(self)
        # persist values
        self.running = False
        self.reading = False
        self.reading_file = Event()  # Initialize your event here it here

    def setfilename(self,filename):
        self.filename = filename
        self.reading_file.set()  # This awakens the reader

    def _start(self):
        self.running = True
        self.reading_file.wait()  # Thread will be stopped until readfilename is called
        self.startread()

Стоит изучить еще один примитив синхронизации queue.Queue.Это может быть полезно, если вы хотите обработать более одного имени файла.

Шаблон, который вы описываете в своем вопросе, называется Ожидание при занятости , и его следует по возможности избегать.

...