2016-08-05 2 views
0

Я использую библиотеку sigslot для запуска сигналов в функции. Эта функция работает в потоке с использованием QtConcurrent :: run, а сигналы связаны в основном потоке. Он работает нормально, за исключением того, что соединение сигнала не работает каждый раз (скажем, около 25% отказа).Сигналы sigslot по потокам

Это неустойчивое поведение является проблематичным, и я не могу найти решение. Сигналы в библиотеке sigslot имеют разные параметры в зависимости от контекста многопоточности, но ни одна из них не устраняет проблему.

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

Любой намек был бы очень признателен.

Обновление: По какой-то причине, используя отчаянную попытку sigslot :: single_threaded, похоже, дает лучшие результаты.

signal1<int, single_threaded> Sig1; 

Я не говорю, что это решение проблемы, поскольку для меня это не имеет смысла. Как поясняется в документации: Single Threaded В однопоточном режиме библиотека не пытается защитить свои внутренние структуры данных по потокам. Поэтому важно, чтобы все вызовы конструкторам, деструкторам и сигналам должны существовать в пределах одного потока.

Update 2:

Вот MWE. Но результаты довольно случайны. Иногда он полностью работает, иногда не все. Я знаю, это звучит странно, но в этом проблема. Я также попробовал boost :: signals2 вместо sigslot, но результат совершенно такой же. Там в исполняемый плохой доступ в буст :: signals2 :: мьютекс :: замок()

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 
} 
+0

жаль, что не сделал MWE, я действительно искал глобальный ответ вместо отладки кода (например, «Qt и sigslot не будут работать вместе»). Поскольку поведение неустойчиво и контекст довольно запутанный, я думал, что не стоит делать пример – brahmin

+0

Самая важная недостающая часть: нет библиотеки «sigslot». Это заброшенный проект, доступный в несколько этапов разложения из разных источников. Добавьте ссылку на версию, которую вы используете. –

+0

Ну, я не знал об этой библиотеке. Я начал использовать, потому что нашел только хорошие отзывы. Я использую эту версию: https://sourceforge.net/p/sigslot/patches/3/ – brahmin

ответ

2

библиотека sigslot Сара Томпсон (если это то, что вы используете) старый, без поддержки, и, кажется, довольно багги. Там нет тестовой упряжи. Исходный источник не компилируется в современных компиляторах. Там есть опечатки, которые были скрыты из-за прежней обработки MSVC шаблонов в виде токенов: очевидно, что части кода никогда не использовались!

Я настоятельно рекомендую вам просто использовать Qt или другую библиотеку сигнальных слотов.

Увы, ваш подход не может работать: sigslot library не имеет представления о контексте потока 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_ обозначает THREADSAFE/стуком.

+0

Спасибо за ответ. На данный момент соединения Qt выглядят нормально. Но вы правы, я не делал никаких определений, чтобы слоты были потокобезопасными. Проблема больше связана с соединениями sigslot, сигнал которого запускается в потоке Qt, но подключается в основном потоке (вместе с слотом sigslot). Но, возможно, я не понял ваш ответ правильно. – brahmin

+0

Опять же, не имеет значения, что происходит там, где потоки различаются, а sigslot не поддерживает его. Внимательно прочитайте документацию: sigslot не знает (и не может быть!) Относительно того, где живут различные объекты. 'QObject :: thread()' существует по уважительной причине. Без такого механизма невозможно реализовать нитевидную систему сигнальных слотов. –

+0

Использование повышения в MWE не дает лучшего результата. Пример, который вы предложили использовать QObject, предназначен для замены sigslot или boost right? Я действительно хочу избежать использования Qt в библиотеке вычислений, которая используется в QtConcurrent :: run, слишком тяжелая, если библиотека используется без GUI. Во всяком случае, это очень странно, теперь в моем коде все выглядит нормально (используя sigslot), но я не уверен, учитывая то, что вы сказали. Программное обеспечение должно быть перекрестной платформой и т. Д., И я боюсь, что какое-то странное поведение может появиться в любое время в будущем. – brahmin

Смежные вопросы