2016-08-05 46 views
0

我正在使用sigslot库来触发函数中的信号。该函数使用QtConcurrent :: run在一个线程中运行,并且信号在主线程中连接。 除了信号连接每次都不工作(假设大约有25%的故障),它的工作方式与预期相当。跨线程的sigslot信号

这种不稳定的行为是有问题的,我找不到解决方案。取决于多线程上下文,sigslot库中的信号具有不同的选项,但它们中没有一个正在解决该问题。

之前努力提振,我真的想找到一个解决方案使用sigslot,因为它是一个很简单的图书馆,我只需要在这部分代码基本使用的信号和槽保持。我不希望为此使用Qt,因为我宁愿将代码的相同部分留给Qt。

任何提示将不胜感激。

更新:由于某种原因,使用作为绝望尝试sigslot :: single_threaded似乎让路更好的结果。

signal1<int, single_threaded> Sig1; 

我不是说它解决了问题,因为它对我没有意义。如文档中所述: 单线程在单线程模式下,库不会尝试跨线程保护其内部数据结构 。因此,所有对构造函数,析构函数和信号 的调用都必须存在于单个线程中。

更新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

最重要的缺失部分是:没有“the”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_前缀代表线程/ thunk的。

+0

感谢您的回答。 Qt连接现在看起来没问题。但是你是对的,我没有做出任何具体的插槽是线程安全的。问题更多地涉及sigslot连接,该信号在Qt线程中触发,但在主线程中(与sigslot插槽一起)连接。但也许我没有正确理解你的答案。 – brahmin

+0

再说一遍,发生什么事情并不重要,只要线程不同,那么sigslot不支持它。仔细阅读文档:sigslot不知道(不能有任何!)关于各种物体在哪里生活。 'QObject :: thread()'有很好的理由。没有这种机制,线程安全信号槽系统就不可能实现。 –

+0

在MWE中使用boost并没有给出更好的结果。你提出的使用QObject的例子是为了替代sigslot或boost?我真的想要避免在QtConcurrent :: run中使用的计算库中使用Qt,但是在没有GUI的情况下使用库时,这太重了。无论如何,这是非常奇怪的,现在在我的代码中看起来工作正常(使用sigslot),但我不确定你说的是什么。软件应该是跨平台等,我担心将来会出现一些奇怪的行为 – brahmin