Прерывистая ошибка потока Python, «основной поток не находится в основном цикле»

Отец средних лет (инженер-электрик не программист по профессии) пытается научить мою 13-летнюю дочернюю электронику и программирование. До сих пор я люблю Python. Я создаю программу для отображения температуры по всему нашему дому с помощью датчиков tkinter GUI и DS18B20.

Мы собрали программу ниже, прочитав книги, онлайн-исследования и используя Stack Overflow для устранения проблем с ошибками (этот сайт скалы!).

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

Во второй раз и все последующие времена мы получаем это сообщение об ошибке:

Traceback (most recent call last): File "/home/pi/Code-working-library/stackoverflow-paste.py", line 140, in <module> app.equipTemp.set(tempread) File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 203, in set return self._tk.globalsetvar(self._name, value) RuntimeError: main thread is not in main loop 

Обратите внимание: наше понимание заключается в том, что для того, чтобы обновить обновляемые временные окна и обновить метки с нашего сенсора (DS18B20), нам нужно было использовать поток. Образец кода, с которого мы начали, содержит операторы _init_ только с одним подчеркиванием, предшествующим и конечным – не знаю, почему, если я добавлю второй знак подчеркивания, я получаю сообщения об ошибках. Код окна обновления, который мы использовали в качестве основы, получен от форума «Малина Pi»

Вот наш код:

 from Tkinter import * import tkFont import os import glob import time import subprocess import re import sys import time import threading import Image import ImageTk os.system('modprobe w1-gpio') os.system('modprobe w1-therm') #28-000005c6ba08 sensors = ['28-000005c6ba08'] sensors1 = ['28-000005c70f69'] def read_temp_raw(): catdata = subprocess.Popen(['cat',device_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) out,err = catdata.communicate() out_decode = out.decode('utf-8') lines = out_decode.split('\n') return lines def read_temp(): lines = read_temp_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = read_temp_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: temp_string = lines[1][equals_pos+2:] temp_c = float(temp_string) / 1000.0 temp_f = temp_c * 9.0 / 5.0 + 32.0 return temp_f ########### build window ################### bground="grey" class App(threading.Thread): def _init_(self): threading.Thread._init_(self) self.start() def callback(self): self.root.quit() def run(self): #Make the window self.root = Tk() self.root.wm_title("Home Management System") self.root.minsize(1440,1000) self.equipTemp = StringVar() self.equipTemp1 = StringVar() self.equipTemp2 = StringVar() self.customFont = tkFont.Font(family="Helvetica", size=16) # 1st floor Image img = Image.open("HOUSE-PLANS-01.png") photo = ImageTk.PhotoImage(img) Label1=Label(self.root, image=photo) Label1.place(x=100, y=100) # 2nd floor img2 = Image.open("HOUSE-PLANS-02.png") photo2 = ImageTk.PhotoImage(img2) Label1=Label(self.root, image=photo2) Label1.place(x=600, y=100) # Basement image img3 = Image.open("HOUSE-PLANS-03.png") photo3 = ImageTk.PhotoImage(img3) Label1=Label(self.root, image=photo3) Label1.place(x=100, y=500) # Attic Image img4 = Image.open("HOUSE-PLANS-04.png") photo4 = ImageTk.PhotoImage(img4) Label1=Label(self.root, image=photo4) Label1.place(x=600, y=500) # House Isometric Image img5 = Image.open("house-iso.png") photo5 = ImageTk.PhotoImage(img5) Label1=Label(self.root, image=photo5) Label1.place(x=1080, y=130) #Garage Temp Label Label2=Label(self.root, textvariable=self.equipTemp, width=6, justify=RIGHT, font=self.customFont) Label2.place(x=315, y=265) print "start monitoring and updating the GUI" self.root.mainloop() #start monitoring and updating the GUI ########### Start Loop ################### print "starting app" app = App() app.start() print "app started" ################### Begin ds18b20 function ############## while True: # 28-000005c6ba08 i = "28-000005c6ba08" base_dir = '/sys/bus/w1/devices/' device_folder = glob.glob(base_dir + i)[0] device_file = device_folder + '/w1_slave' tempread=round(read_temp(),1) app.equipTemp.set(tempread) time.sleep(5) ##################### END ds18b20 Function ###### 

  • Как захватить вывод сценария оболочки, запущенного в отдельном процессе, в wxPython TextCtrl?
  • Pandas: частота штрих-кодов
  • Суммируйте цифры числа - python
  • Добавьте ярлыки x и y в сюжет панды
  • Как сделать декораторы необязательно включать или выключать
  • Как создать собственный класс исключений с несколькими init args pickleable
  • Многострочные записи журнала в syslog
  • В чем причина выполнения двойной вилки при создании демона?
  • 2 Solutions collect form web for “Прерывистая ошибка потока Python, «основной поток не находится в основном цикле»”

    Вам нужно запустить GUI-код в основном потоке, и ваш код чтения температуры должен быть в фоновом потоке. Безопасно обновлять графический интерфейс в основном потоке, так что вы можете передавать данные температуры, которые вы читаете из фонового потока, обратно в основной поток через Queue , и иметь основной поток, периодически проверяющий данные в очереди, используя self.root.after() :

     from Tkinter import * import tkFont import os import glob import time import threading import Image import Queue def update_temp(queue): """ Read the temp data. This runs in a background thread. """ while True: # 28-000005c6ba08 i = "28-000005c6ba08" base_dir = '/sys/bus/w1/devices/' device_folder = glob.glob(base_dir + i)[0] device_file = device_folder + '/w1_slave' tempread=round(read_temp(),1) # Pass the temp back to the main thread. queue.put(tempread) time.sleep(5) class Gui(object): def __init__(self, queue): self.queue = queue #Make the window self.root = Tk() self.root.wm_title("Home Management System") self.root.minsize(1440,1000) self.equipTemp = StringVar() self.equipTemp1 = StringVar() self.equipTemp2 = StringVar() self.customFont = tkFont.Font(family="Helvetica", size=16) # 1st floor Image img = Image.open("HOUSE-PLANS-01.png") photo = ImageTk.PhotoImage(img) Label1=Label(self.root, image=photo) Label1.place(x=100, y=100) # 2nd floor img2 = Image.open("HOUSE-PLANS-02.png") photo2 = ImageTk.PhotoImage(img2) Label1=Label(self.root, image=photo2) Label1.place(x=600, y=100) # Basement image img3 = Image.open("HOUSE-PLANS-03.png") photo3 = ImageTk.PhotoImage(img3) Label1=Label(self.root, image=photo3) Label1.place(x=100, y=500) # Attic Image img4 = Image.open("HOUSE-PLANS-04.png") photo4 = ImageTk.PhotoImage(img4) Label1=Label(self.root, image=photo4) Label1.place(x=600, y=500) # House Isometric Image img5 = Image.open("house-iso.png") photo5 = ImageTk.PhotoImage(img5) Label1=Label(self.root, image=photo5) Label1.place(x=1080, y=130) #Garage Temp Label Label2=Label(self.root, textvariable=self.equipTemp, width=6, justify=RIGHT, font=self.customFont) Label2.place(x=315, y=265) print "start monitoring and updating the GUI" # Schedule read_queue to run in the main thread in one second. self.root.after(1000, self.read_queue) def read_queue(self): """ Check for updated temp data""" try: temp = self.queue.get_nowait() self.equipTemp.set(temp) except Queue.Empty: # It's ok if there's no data to read. # We'll just check again later. pass # Schedule read_queue again in one second. self.root.after(1000, self.read_queue) if __name__ == "__main__": queue = Queue.Queue() # Start background thread to get temp data t = threading.Thread(target=update_temp, args=(queue,)) t.start() print "starting app" # Build GUI object gui = Gui(queue) # Start mainloop gui.root.mainloop() 

    Редактировать:

    После того, как вы посмотрите на исходный код tkinter, а также на отслеживатель ошибок Python, похоже, что в отличие от почти любой другой библиотеки GUI, tkinter предназначен для потокобезопасности, поскольку вы запустите mainloop в основном потоке приложения. См. Ответ, который я добавил здесь для получения дополнительной информации, или перейдите к разрешенной проблеме безопасности потоков tkinter в Python. Если источник tkinter и трекер ошибок Python верны, это будет означать, что до тех пор, пока вы запустите mainloop в основном потоке, вы можете с радостью вызвать gui.equipTemp.set() непосредственно из потока чтения температуры – нет необходимости в Queue . И в моем тестировании это действительно отлично работает.

    Инструменты GUI не являются потокобезопасными. Вы можете создавать и изменять свой графический интерфейс только из основного потока. Поскольку чтение температуры не займет много времени, вы можете удалить весь код резьбы и использовать метод after -t из Tk.

    Функция read_temp_raw очень сложна:

     def read_temp_raw(): with open(device_file) as temp: return temp.read().split('\n') 
    Python - лучший язык программирования в мире.