Сигналы sigslot через потоки
Я использую библиотеку sigslot для запуска сигналов в функции. Эта функция выполняется в потоке с использованием QtConcurrent::run, а сигналы подключаются в основном потоке. Это вполне работает, как и ожидалось, за исключением того, что сигнальное соединение не работает каждый раз (скажем, около 25% сбоев).
Это ошибочное поведение проблематично, и я не могу найти решение. Сигналы в библиотеке sigslot имеют разные опции в зависимости от контекста многопоточности, но ни один из них не решает проблему.
Прежде чем пытаться повысить, я действительно хотел бы найти решение для продолжения использования sigslot, так как это довольно простая библиотека, и мне нужно только базовое использование сигналов и слотов в этой части кода. И я не хочу использовать Qt для этого, потому что я предпочитаю оставить эту же часть кода свободной от Qt.
Любая подсказка будет высоко ценится.
Обновление: по какой-то причине использование в качестве отчаянной попытки sigslot:: single_threaded дает лучшие результаты.
signal1<int, single_threaded> Sig1;
Я не говорю, что это решает проблему, так как это не имеет смысла для меня. Как объяснено в документации: Однопоточный В однопоточном режиме библиотека не пытается защитить свои внутренние структуры данных между потоками. Поэтому важно, чтобы все вызовы конструкторов, деструкторов и сигналов существовали в одном потоке.
Обновление 2:
Здесь MWE. Но результаты довольно случайны. Иногда это полностью работает, иногда не все. Я знаю, это звучит странно, но это проблема. Я также пробовал повысить:: сигналы2 вместо sigslot, но результат совершенно тот же. В boost:: signal2::mutex::lock() есть исполнимый неверный доступ
class A {
public :
A() {}
~A() {}
sigslot::signal1<int, sigslot::multi_threaded_local> sigslot_signal;
boost::signals2::signal<void (int)> boost_signal;
void func_sigslot() {
for (int i=0;i<4;i++) {
sigslot_signal.emit_signal(i);
}
}
void func_boost() {
for (int i=0;i<4;i++) {
boost_signal(i);
}
}
};
class B : public sigslot::has_slots<sigslot::multi_threaded_local> {
public :
B() {}
~B() {}
void test(int i) {
std::cout << "signal triggered, i=" << i << std::endl;
}
};
void main() {
A a;
B b;
a.sigslot_signal.connect_slot(&b, &B::test);
a.boost_signal.connect(boost::bind(&B::test, &b, _1));
QtConcurrent::run(&a, &A::func_sigslot);//->crashes when signal emitted
QtConcurrent::run(&a, &A::func_boost);//->crashes when signal emitted
boost::thread t1(boost::bind(&A::func, &a));
t1.join();//works fine
}
1 ответ
Библиотека sigslot Сары Томпсон (если это то, что вы используете) старая, неподдерживаемая и кажется довольно глючной. Там нет тестовых проводов любого рода. Первоисточник не компилируется под современные компиляторы. Там есть опечатки, которые были скрыты из-за прежней обработки шаблонов MSVC как списков токенов: очевидно, части кода никогда не использовались!
Я настоятельно рекомендую вам просто использовать Qt или другую библиотеку сигнальных слотов.
Увы, ваш подход не может работать: библиотека sigslot не имеет представления о контекстах потоков Qt и не интегрируется с циклом событий Qt. Слоты вызываются из неправильного контекста потока. Так как вы, вероятно, не написали свои слоты для обеспечения безопасности потоков, они не делают правильных действий и, похоже, не работают.
Поддержка потоков библиотеки sigslot защищает только собственные данные библиотеки, а не ваши. Установка политик многопоточности влияет только на данные библиотеки. Это резко контрастирует с Qt, где каждый QObject
Российский контекст потока известен и позволяет системе сигнальных слотов действовать безопасно.
Для того, чтобы заставить его работать, вы должны предоставить потокобезопасный интерфейс во всех QObject
чьи слоты вы вызываете. Это может быть так просто, как:
class Class : public QObject {
Q_OBJECT
public:
Class() {
// This could be automated via QMetaObject and connect overload
// taking QMetaMethod
connect(this, &Class::t_slot, this, &Class::slot);
}
Q_SIGNAL void t_slot();
Q_SLOT slot() { ... }
}
Вместо подключения к slot()
, присоединиться t_slot()
, где t_
префикс означает потокобезопасный /thunk.