Qt: Как избежать тупика, когда несколько сигналов в очереди вызывают один и тот же слот

Error: Access is denied сообщает, что шаблон недоступен. Попробуйте открыть шаблон в своем браузере. Что-то вроде этого: http: //my_project/partials1/view3.html . Чтобы увидеть полный URL-адрес, используемый вашим приложением, используйте консоль dubug (вкладка XHR).

0
задан zuoheng.deng 17 January 2019 в 03:06
поделиться

2 ответа

Требование, чтобы "someOperation is not reentrant" было нечетным. Что должно произойти, если попытка возвращения? Учитывая, что someOperation можно вызывать только из потока main, я вижу только два варианта ...

  1. Блокировать полностью мьютексом / барьером и т. Д., Как вы пытались.
  2. Блокировать на основе счетчика уровня рекурсии и вращать цикл событий, пока этот счетчик не уменьшится до нуля.

1) Полностью заблокирует цикл событий потока, не позволяя корректно функционировать текущему диалоговому окну сообщений.

2) Разрешит одновременное ведение всех диалогов сообщений, а не их сериализацию.

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

Одним из вариантов может быть использование отдельного QObject экземпляра производного класса самостоятельно QThread. Рассмотрим следующее ...

class signal_serialiser: public QObject {
  Q_OBJECT;
signals:
  void signal1();
  void signal2();
  void signal3();
};

Если экземпляр signal_serialiser перемещается в свой собственный поток, он может действовать как очередь для буферизации и пересылки различных сигналов, если используются подходящие типы соединений. В вашем коде у вас есть ...

QObject::connect(w, SIGNAL(signal1()), a, SLOT(slot1()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal2()), a, SLOT(slot2()), Qt::QueuedConnection);
QObject::connect(w, SIGNAL(signal3()), a, SLOT(slot3()), Qt::QueuedConnection);

Измените это на ...

signal_serialiser signal_serialiser;
QObject::connect(w, SIGNAL(signal1()), &signal_serialiser, SIGNAL(signal1()));
QObject::connect(w, SIGNAL(signal2()), &signal_serialiser, SIGNAL(signal2()));
QObject::connect(w, SIGNAL(signal3()), &signal_serialiser, SIGNAL(signal3()));

/*
 * Note the use of Qt::BlockingQueuedConnection for the
 * signal_serialiser --> A connections.
 */
QObject::connect(&signal_serialiser, SIGNAL(signal1()), a, SLOT(slot1()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal2()), a, SLOT(slot2()), Qt::BlockingQueuedConnection);
QObject::connect(&signal_serialiser, SIGNAL(signal3()), a, SLOT(slot3()), Qt::BlockingQueuedConnection);
QThread signal_serialiser_thread;
signal_serialiser.moveToThread(&signal_serialiser_thread);
signal_serialiser_thread.start();

Я только провел базовое тестирование, но, похоже, оно дает желаемое поведение.

0
ответ дан G.M. 17 January 2019 в 03:06
поделиться

Это потому, что ваша функция void someOperation() не является реентерабельной .

Статические функции QMessageBox охватывают свой собственный цикл обработки событий, который неоднократно вызывает QCoreApplication::processEvents():

  1. Выполнение первого вызова someOperation() застревает в QMessageBox::warning(...).
  2. ]
  3. Там exec() вызывает processEvents(), 3. который видит второй сигнал
  4. и снова вызывает someOperation()
  5. , где попытка повторной блокировки mutex не удалась.

Как решить эту проблему, зависит от того, чего вы хотите достичь ...


О вашем общем подходе к QThread: Вы делаете это неправильно.
(Эта ссылка дает хорошее начало в теме, но не является полным решением.)

Вы создаете и запускаете фоновый поток. Но этот поток только испустит три сигнала и затем закончится.

Слоты будут вызываться в основном цикле событий (GUI), потому что это сходство потоков вашего A *a.

Чтобы слоты выполнялись в фоновом режиме, вам необходимо:

  1. создать экземпляр A без родителя: A *a = new A();
  2. создать экземпляр Worker с приложением как родитель: Worker *w = new Worker(&app); (или ни с чем, по крайней мере, не с a)
  3. изменить привязку потока вашего экземпляра A: a->moveToThread(Worker);
  4. не переопределять Worker::run() или, если вы действительно хотите (см. пункт 5), вызовите базовую реализацию: QThread::run();
  5. испускают сигналы из main (вы можете испускать их из run (), но это не обязательно). [1129 ] [Тысяча сто тридцать одна]
0
ответ дан Martin Hennings 17 January 2019 в 03:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: