Модуль queue (встроенный в Python): при добавлении второго задания в очередь, оно сразу же начинает выполняться, но первое ещё не завершено
Я изучаю Python и фреймворк PyQt6 (а точнее PySide6).
Моя идея в том, что в основном потоке программы задания добавляются в очередь (модуль queue), а выполняются эти задания в одном отдельном потоке.
У меня получилось сделать простую программу и в ней задания выполняются по очереди, пока я добавляю задания, выполняется первое задание, после окончания первого задания начинает выполняться второе и тд, то есть все как я и хотел.
Но теперь я сделал программу немного посложнее и в ней так же queue
обрабатывается в отдельном потоке.
Но происходит странная вещь, с которой я никак не могу разобраться.
А именно - пока выполняется первое задание, я назначаю второе задание и оно сразу же начинает выполняться.
Причем оно выполняется с того же места, где было прервано первое задание.
При этом никаких ошибок и исключений не возникает.
Пришел к мысли, что проблема в потоке, который обрабатывает задания из очереди.
Программа, которую я пытаюсь реализовать, нужна для тестового стенда. На этот стенд устанавливается n-ное количество устройств одного вида, каждое в свой слот, при этом некоторые слоты могут оставаться пустыми.
С помощью программы выбирается нужный слот, выбираются необходимые тесты,
именно для этого слота и нажимается кнопка запуск.
Задание попадает в очередь, а программа начинает гонять тесты по первому устройству.
Далее для всех остальных устройств на стенде таким же образом назначаются тесты и отправляются в очередь при нажатии на кнопку запуск.
Стенд не может одновременно тестировать все устройства в слотах (из-за своего собственного устройства), а только по очереди, поэтому решил использовать очередь (модуль queue из Python) и отдельный поток (QThread из PySide6).
На данный момент грешу именно на часть кода в потоке, которая как раз получает и обрабатывает задания из очереди, что я там что-то неправильно сделал, так как остальные части этого механизма реализованы один в один с другой программой, в которой эта идея работает.
По крайней мере, мне так кажется.
UPD: Добавил минимальный воспроизводимый пример, заранее извиняюсь за длинный код, уменьшил как смог до 600 строк кода, некорректное поведение сохранилось.
При запуске программы открывается окно с 4-мя слотами, чтобы назначить проверки для слота, нужно сделать двойной клик на вертикальном прогресс-баре, тогда откроется окно с возможностью выбора проверок, можно выбрать тип устройства в комбобоксе (2 вида), после нажатия кнопки "Запуск" сразу же начнется проверка на выбранном слоте, при этом выбранные проверки будут "подсвечены" голубоватого цвета индикатором напротив назначенных проверок, текущая проверка - желтым цветом, пройденная - зеленым.
import sys, time
import queue
from PySide6.QtWidgets import (
QApplication,
QCheckBox,
QComboBox,
QLabel,
QGridLayout,
QMainWindow,
QProgressBar,
QPushButton,
QHBoxLayout,
QVBoxLayout,
QWidget,
)
from PySide6.QtCore import Qt, Signal, QThread
from PySide6.QtGui import QMouseEvent
checks_list = [
"Потребляемая мощность в рабочем режиме", # 0
"Потребляемая мощность в режиме КЗ", # 1
"Прогрев", # 2
"Опр-е основной приведенной погрешности", # 3
"Опр-е напр-я питания на холостом ходу", # 4
"Опр-е остаточного напряжения на датчике", # 5
"Определение падения напряжения на входе", # 6
]
mibs_list = [
"DEV-211",
"DEV-212",
]
class MibWorker(QThread):
# Сигнал для обновления цветовой метки Канала о состоянии: проверка пройдена успешно #зеленый
update_slot_channel_label_pass = Signal(int)
# Сигнал для обновления цветовой метки Канала о состоянии: проверка завершилась ошибкой #красный
update_slot_channel_label_nopass = Signal(int)
# Сигнал для обновления цветовой метки Канала о состоянии:
# проверка проходится и ещё не завершена #желтый
update_slot_channel_label_passes = Signal(int)
# Сигнал для обновления поля - текущая проверка
update_text_edit_signal = Signal(str)
count_process = 0
def __init__(self, queue):
super().__init__()
self.queue = queue
def stopRunning(self):
self.terminate()
self.wait()
self.count_process = 0
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Проверка окончена"
)
def routine(self, num_check):
process = 1
y = 0
while process == 1:
for _ in range(5):
y += 1
time.sleep(1)
process = 0
if y == 5:
self.update_slot_channel_label_pass.emit(num_check)
else:
self.update_slot_channel_label_nopass.emit(num_check)
def powerConsumptionInOperatingMode(self, num_check):
self.count_process += 1
self.update_slot_channel_label_passes.emit(num_check)
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Потребляемая мощность в рабочем режиме",
)
self.routine(num_check)
def powerConsumptionInShortCircuitMode(self, num_check):
self.count_process += 1
self.update_slot_channel_label_passes.emit(num_check)
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Потребляемая мощность в режиме КЗ",
)
self.routine(num_check)
def warmingUp(self, num_check):
self.count_process += 1
self.update_slot_channel_label_passes.emit(num_check)
self.update_text_edit_signal.emit(f"Этап {self.count_process} Прогрев")
self.routine(num_check)
def determinationOfTheMainReducedError(self, num_check):
self.count_process += 1
self.update_slot_channel_label_passes.emit(num_check)
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Определение основной приведенной погрешности"
)
self.routine(num_check)
def determinationOfTheSupplyVoltageAtIdle(self, num_check):
self.count_process += 1
self.update_slot_channel_label_passes.emit(num_check)
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Определение напряжения питания на холостом ходу",
)
self.routine(num_check)
def determinationOfTheResidualVoltageOnTheSensor(self, num_check):
self.update_slot_channel_label_passes.emit(num_check)
self.count_process += 1
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Определение остаточного напряжения на датчике",
)
self.routine(num_check)
def determinationOfTheVoltageDropAtTheInput(self, num_check):
self.update_slot_channel_label_passes.emit(num_check)
self.count_process += 1
self.update_text_edit_signal.emit(
f"Этап {self.count_process} Определение падения напряжения на входе",
)
self.routine(num_check)
def checksList(self, task):
if 0 in task:
self.powerConsumptionInOperatingMode(0)
if 1 in task:
self.powerConsumptionInShortCircuitMode(1)
if 2 in task:
self.warmingUp(2)
if 3 in task:
self.determinationOfTheMainReducedError(3)
if 4 in task:
self.determinationOfTheSupplyVoltageAtIdle(4)
if 5 in task:
self.determinationOfTheResidualVoltageOnTheSensor(5)
if 6 in task:
self.determinationOfTheVoltageDropAtTheInput(6)
def run(self):
while True:
task = self.queue.get()
self.ch1_list = task[2][:]
self.checksList(self.ch1_list)
self.queue.task_done()
self.ch1_list.clear()
self.count_process = 0
class MibWindow(QWidget):
mib_index_signal = Signal(list)
mib_worker_stop_signal = Signal()
mib_close_signal = Signal()
mib_index = 0
process_list_ch1 = []
process_list_ch2 = []
mib_channel_index = 0
def __init__(self, num_slot=None, **kwargs):
super().__init__(**kwargs)
self.num_slot = num_slot
self.initializeUI()
def initializeUI(self):
self.setWindowTitle("Окно назначения задания")
self.setUpMibWindow()
def setUpMibWindow(self):
self.name_process = QLabel("Наименование проверки")
self.name_process.setWordWrap(True)
self.name_process.setAlignment(
Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignCenter
)
# Формирование списка объектов - текстовых полей с наименованиями проверок
self.slot_process_list = []
self.slot_processes = [QLabel() for i in range(1, 7)]
for index, process in enumerate(self.slot_processes):
process.setMinimumHeight(20)
process.setEnabled(False)
process.setText(checks_list[index])
self.slot_process_list.append(process)
self.title_name_process = QLabel("Выбор проверки")
self.title_name_process.setWordWrap(True)
self.title_name_process.setAlignment(
Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignCenter
)
self.title_channel_1 = QLabel("Канал 1")
# Формирование списка объектов - чекбоксов для канала 1
self.slot_cbox_ch1_list = []
self.slot_ch1_cboxes = [QCheckBox() for i in range(1, 7)]
for cbox in self.slot_ch1_cboxes:
self.slot_cbox_ch1_list.append(cbox)
self.all_check = QPushButton("Выбрать все")
self.all_check.clicked.connect(self.allCheck)
self.no_check = QPushButton("Снять все")
self.no_check.clicked.connect(self.noCheck)
bottom_box = QHBoxLayout()
bottom_box.addWidget(self.all_check)
bottom_box.addWidget(self.no_check)
self.mib_list = [
"MIB-211",
"MIB-212",
]
self.mib_combobox = QComboBox()
self.mib_combobox.addItems(self.mib_list)
self.mib_combobox.activated.connect(self.switchMib)
self.launch_button = QPushButton("Запуск")
self.launch_button.clicked.connect(self.launchUp)
self.stop_button = QPushButton("Стоп")
self.stop_button.clicked.connect(self.stopProcess)
grid = QGridLayout()
grid.setAlignment(Qt.AlignmentFlag.AlignTop)
# 0-й столбец
grid.addWidget(self.name_process, 0, 0, 1, 2)
for process in self.slot_process_list:
row = 2 + self.slot_process_list.index(process)
grid.addWidget(process, row, 0, 1, 1)
# 2-й столбец
grid.addWidget(self.title_name_process, 0, 2, 1, 2)
grid.addWidget(self.title_channel_1, 1, 2)
for cbox in self.slot_cbox_ch1_list:
row = 2 + self.slot_cbox_ch1_list.index(cbox)
grid.addWidget(cbox, row, 2, 1, 1, Qt.AlignmentFlag.AlignCenter)
# 4-й столбец
grid.addWidget(self.mib_combobox, 1, 4)
grid.addWidget(self.launch_button, 5, 4)
grid.addWidget(self.stop_button, 6, 4)
grid.addLayout(bottom_box, 16, 0, 1, 4, Qt.AlignmentFlag.AlignHCenter)
grid.setColumnStretch(4, 10)
self.setLayout(grid)
def allCheck(self):
for cbox in self.slot_cbox_ch1_list:
cbox.setChecked(True)
def noCheck(self):
for cbox in self.slot_cbox_ch1_list:
cbox.setChecked(False)
def launchUp(self):
self.process_list_ch1.clear()
for cbox in self.slot_cbox_ch1_list:
if cbox.isChecked():
ind1 = self.slot_cbox_ch1_list.index(cbox)
self.process_list_ch1.append(ind1)
self.channels = 0
self.check_list = []
self.check_list.append(self.num_slot)
self.check_list.append(self.mib_index)
self.check_list.append(self.process_list_ch1)
# Отправлен сигнал - задание в очередь (номер слота,
# индекс устр-ва, список проверок К1)
self.mib_index_signal.emit(self.check_list)
def switchMib(self, index):
self.mib_index = index
self.noCheck()
def stopProcess(self):
# Сигнал для остановки проверок на слоте
self.mib_worker_stop_signal.emit()
class MibSlot(QWidget):
num_slot_signal = Signal(int)
mib_slot_close_signal = Signal()
mib_slot_signal = Signal(
list,
)
mib_worker_stop_signal = Signal()
def __init__(self, num_slot=None, **kwargs):
super().__init__(**kwargs)
self.num_slot = num_slot
self.mib_window = MibWindow(self.num_slot)
self.mib_window.mib_index_signal.connect(self.workMibSlot_1)
self.mib_window.mib_close_signal.connect(self.closeMibWindow)
self.mib_window.mib_worker_stop_signal.connect(self.stopProcess)
self.initializeUI()
def initializeUI(self):
self.setUpMibSlot()
def setUpMibSlot(self):
# 1 - Слот №...
self.slot_title_label = QLabel(f"Слот № {self.num_slot}")
self.slot_title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# 2 - Серийный номер устройства
self.slot_serial_num_label = QLabel("Серийный номер:")
# 3 - Тип устройства
self.slot_device_type_label = QLabel("MIB")
self.slot_device_type_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# 4 - Прогресс-бар
self.slot_pbar = QProgressBar()
self.slot_pbar.setValue(0)
self.slot_pbar.setOrientation(Qt.Orientation.Vertical)
# 6 - Первый столбец индикаторов проверок
# Заголовок столбца
self.slot_name_channel_1_label = QLabel("Канал 1")
self.slot_name_channel_1_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Формирование списка объектов - цветовых индикаторов проверок для канала 1
self.slot_channel_1_label_list = []
self.slot_channel_1_labels = [QLabel() for i in range(6)]
for label in self.slot_channel_1_labels:
label.setMaximumSize(10, 10)
self.slot_channel_1_label_list.append(label)
# 8 - Третий столбец - наименование проверки
# Заголовок столбца
self.names_checks_label = QLabel("Наименование проверки")
self.names_checks_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
# Формирование списка объектов - текстовых полей с наименованиями проверок
self.slot_name_check_label_list = []
self.slot_name_check_labels = [QLabel() for i in range(6)]
for index, label in enumerate(self.slot_name_check_labels):
label.setText(checks_list[index])
self.slot_name_check_label_list.append(label)
# 9 - Оставшееся время до конца проверки
self.slot_time_label = QLabel("Оставшееся время:")
# 10 - Этап проверки (текст, какая идет проверка в данный момент)
self.slot_step_label = QLabel("Текущая проверка:")
grid_slot = QGridLayout()
grid_slot.setVerticalSpacing(5)
grid_slot.setContentsMargins(5, 5, 5, 5)
# 0-й столбец
grid_slot.addWidget(self.slot_title_label, 0, 0, 1, 12)
grid_slot.addWidget(self.slot_serial_num_label, 1, 0, 1, 12)
grid_slot.addWidget(self.slot_device_type_label, 2, 0, 1, 5)
grid_slot.addWidget(self.slot_pbar, 3, 0, 14, 2)
grid_slot.addWidget(self.slot_time_label, 17, 0, 1, 12)
grid_slot.addWidget(self.slot_step_label, 18, 0, 1, 12)
# 5-й столбец
grid_slot.addWidget(self.slot_name_channel_1_label, 2, 5, 1, 3)
# 6-й столбец
for label in self.slot_channel_1_label_list:
row = 3 + self.slot_channel_1_label_list.index(label)
grid_slot.addWidget(label, row, 6, 1, 1)
# 11-й столбец
grid_slot.addWidget(self.names_checks_label, 2, 11, 1, 1)
for label in self.slot_name_check_label_list:
row = 3 + self.slot_name_check_label_list.index(label)
grid_slot.addWidget(label, row, 11, 1, 1)
self.setLayout(grid_slot)
self.num_slot_signal.emit(self.num_slot)
def eventFilter(self, obj, event):
if (
isinstance(obj, QProgressBar)
and event.type() == QMouseEvent.Type.MouseButtonDblClick
):
if self.mib_window.isVisible():
self.mib_window.hide()
else:
if not self.mib_window.isVisible():
self.mib_window.show()
else:
self.mib_window.close()
self.mib_window = MibWindow()
self.mib_window.mib_index_signal.connect(self.workMibSlot_1)
self.mib_window.mib_close_signal.connect(self.closeMibWindow)
self.mib_window.show()
return QWidget.eventFilter(self, obj, event)
def workMibSlot_1(self, check_list):
self.mib_slot_signal.emit(check_list)
def closeMibWindow(self):
self.mib_slot_close_signal.emit()
def stopProcess(self):
self.mib_worker_stop_signal.emit()
class BasicWindow(QMainWindow):
window_close_signal = Signal()
window_ignore_signal = Signal()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.queue = queue.Queue()
self.worker_mib = MibWorker(self.queue)
self.process_list_ch1 = []
self.process_list_ch2 = []
self.initializeUI()
def initializeUI(self):
self.setWindowTitle("Главное окно программы")
self.setUpBasicWindow()
self.show()
def setUpBasicWindow(self):
# Формирование списка объектов - слотов для главного окна
self.slot_mib_list = []
self.slot_list = [MibSlot(i) for i in range(1, 5)]
for mib in self.slot_list:
mib.setObjectName("Slot")
mib.mib_slot_signal.connect(self.workMibSlot_1)
mib.mib_slot_close_signal.connect(self.closeMibWindow)
mib.slot_pbar.installEventFilter(mib)
self.slot_mib_list.append(mib)
self.slot_h_box_list = []
h_boxes = [QHBoxLayout() for i in range(4)]
for index, box in enumerate(h_boxes):
box.addWidget(self.slot_mib_list[index])
self.slot_h_box_list.append(box)
self.slot_widget_list = []
widgets = [QWidget() for i in range(4)]
for index, widget in enumerate(widgets):
widget.setLayout(self.slot_h_box_list[index])
self.slot_widget_list.append(widget)
# Макет расположения слотов
grid = QGridLayout()
for row in range(2):
if row == 0:
for col in range(2):
grid.addWidget(self.slot_widget_list[col], row, col, 1, 1)
elif row == 1:
for col in range(2):
grid.addWidget(self.slot_widget_list[col + 2], row, col, 1, 1)
# Создание поля рабочего пространства
self.workspace = QWidget()
self.workspace.setLayout(grid)
main_v_box = QVBoxLayout()
main_v_box.addWidget(self.workspace)
# Установка основного макета окна
container = QWidget()
container.setLayout(main_v_box)
self.setCentralWidget(container)
def worker_thread(self):
self.worker_mib.update_text_edit_signal.connect(self.updateTextEdit)
self.worker_mib.update_slot_channel_label_pass.connect(self.processPass)
self.worker_mib.update_slot_channel_label_nopass.connect(self.processNoPass)
self.worker_mib.update_slot_channel_label_passes.connect(self.processPasses)
self.slot_mib_list[self.num_slot].mib_worker_stop_signal.connect(
self.worker_mib.stopRunning
)
self.worker_mib.finished.connect(self.updateTextStep)
self.worker_mib.start()
def workMibSlot_1(self, check_list):
self.num_slot = check_list[0] - 1
self.index_mib = check_list[1]
self.check_list = check_list[2]
self.slot_mib_list[self.num_slot].slot_device_type_label.setText(
mibs_list[self.index_mib]
)
self.scheduledOneOff()
self.scheduledOne()
self.queue.put(check_list)
self.worker_thread()
def closeMibWindow(self):
if self.worker_mib:
self.slot_mib_list[self.num_slot].mib_window.hide()
else:
self.slot_mib_list[self.num_slot].mib_window.close()
def scheduledOne(self):
# подсвечивает индикаторы проверок
# в соответствии со списком выбранных проверок
for proc in self.check_list:
for index, name in enumerate(
self.slot_mib_list[self.num_slot].slot_name_check_label_list
):
if proc == index:
self.slot_mib_list[self.num_slot].slot_channel_1_label_list[
index
].setStyleSheet(
"border: 1px solid black; border-radius: 2px; background-color: #55ffff"
)
def processPass(self, process):
# Если проверка пройдена успешно
# зеленый
self.slot_mib_list[self.num_slot].slot_channel_1_label_list[
process
].setStyleSheet(
"border: 1px solid black; border-radius: 2px; background-color: #33ff00"
)
def processNoPass(self, process):
# Если проверка пройдена не успешно
# красный
self.slot_mib_list[self.num_slot].slot_channel_1_label_list[
process
].setStyleSheet(
"border: 1px solid black; border-radius: 2px; background-color: #ff0000"
)
def processPasses(self, process):
# Если проверка в процессе прохождения
# желтый
self.slot_mib_list[self.num_slot].slot_channel_1_label_list[
process
].setStyleSheet(
"border: 1px solid black; border-radius: 2px; background-color: #ffff00"
)
def updateTextStep(self):
self.slot_mib_list[self.num_slot].slot_step_label.setText(
f"Этап 0 Проверка окончена"
)
def updateProgressBar(self, value):
self.slot_mib_list[self.num_slot].slot_pbar.setValue(value)
def updateTextEdit(self, text):
if text != "":
self.slot_mib_list[self.num_slot].slot_step_label.setText(text)
def updateTimeEdit(self, time):
self.slot_mib_list[self.num_slot].slot_time_label.setText(f"00:{time}")
def scheduledOneOff(self):
for label in self.slot_mib_list[self.num_slot].slot_name_check_label_list:
label.setStyleSheet("color: grey")
for label in self.slot_mib_list[self.num_slot].slot_channel_1_label_list:
label.setStyleSheet(
"border: 1px solid grey; border-radius: 2px; background-color: #f4f4f4"
)
def closeEvent(self, event):
if event:
if self.worker_mib.isRunning():
self.worker_mib.stopRunning()
# Запустить программу
if __name__ == "__main__":
app = QApplication(sys.argv)
window = BasicWindow()
sys.exit(app.exec())
UPD2: в потоке нужно было прописывать сами проверки, а не вызывать их оттуда как функции.
Ответы (1 шт):
Минимально воспроизводимый пример выглядит так:
import re
import sys
import time
import queue
from PySide6.QtWidgets import (
QApplication, QMainWindow, QPushButton, QVBoxLayout,
QWidget, QListWidget, QListWidgetItem, QProgressBar
)
from PySide6.QtCore import QThread, Signal
class WorkerThread(QThread):
# Передаем индекс задачи и ее состояние
update_signal = Signal(int, str)
# Передаем прогресс выполнения
progress_signal = Signal(int)
def __init__(self, task_queue):
super().__init__()
self.task_queue = task_queue
self._running = True # Флаг для управления потоком
def run(self):
while self._running:
try:
# Получаем задачу из очереди
task_id = self.task_queue.get(timeout=1)
# Обновляем статус
self.update_signal.emit(task_id, "In progress")
# Имитация длительной задачи
for i in range(100):
time.sleep(0.05) # Имитация работы
# Обновляем прогресс
self.progress_signal.emit(i + 1)
# Обновляем статус
self.update_signal.emit(task_id, "Completed")
self.task_queue.task_done()
except queue.Empty:
continue # Если очередь пуста, продолжаем ожидать
def stop(self):
self._running = False # Остановка потока
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Queue with QThread Example")
self.task_queue = queue.Queue()
self.count_tasks = self.counter()
# Передаём очередь как аргумент
self.worker_thread = WorkerThread(self.task_queue)
# Тут настраиваем коннект между потоками
self.worker_thread.update_signal.connect(self.update_status)
# Чтоб прогресс обработки был виден в основном потоке
self.worker_thread.progress_signal.connect(self.update_progress)
layout = QVBoxLayout()
self.task_list_widget = QListWidget()
layout.addWidget(self.task_list_widget)
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 100)
layout.addWidget(self.progress_bar)
self.button = QPushButton("Добавить задачу")
self.button.clicked.connect(self.add_task)
layout.addWidget(self.button)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
self.worker_thread.start() # Запускаем поток обработки
def add_task(self):
task_id = self.count_tasks() # Получаем новый ID задачи
self.task_queue.put(task_id) # Добавляем задачу в очередь
item = QListWidgetItem() # Создаем элемент
# Сохраняем ID задачи и стартовый статус
item.setData(0, f"Задача {task_id}: Waiting process")
self.task_list_widget.addItem(item) # Добавляем элемент в список
self.progress_bar.setValue(0)
def counter(self):
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
def update_status(self, task_id, status):
item = self.task_list_widget.item(task_id-1)
item.setText(f"Задача {task_id}: {status}")
def update_progress(self, value):
self.progress_bar.setValue(value)
def closeEvent(self, event):
self.worker_thread.stop() # Останавливаем поток при закрытии окна
self.worker_thread.wait() # Ждем завершения потока
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
^^^ В решени есть очередь и обработка в отдельном потоке.
Я не пытался воспроизвести Вашу проблему,
у меня всё работает:
UPD: У Вас нет никакой проблемы с очередями и потоками.
У Вас проблемы с архитектурой, отсутствие абстракции функционального программирования (бусы однотипных методов в MibWorker), нарушение инкапсуляции в MibSlot (всё что относится к классу должно быть в нём). Например, check_list однозначно должен быть атрибутом экземпляра, и методы обработки сигналов тоже. А в очередь надо добавлять самодостаточный объект self.queue.put(slot1 := MibSlot(1)) - выглядеть это будет немного иначе, т.к. слоты инициализированы при запуске приложения.
И с сигналами надо отправлять идентифицирующие аргументы...
Если у Вас виджет принадлежит одному объекту,
а методы изменяющие его состояние почему-то в другом классе ... ⁉️
Ваш код надо переделывать.

