【发布时间】:2016-08-05 13:07:51
【问题描述】:
我正在使用 sigslot 库来触发函数中的信号。该函数使用 QtConcurrent::run 在线程中运行,信号在主线程中连接。 它按预期工作,除了信号连接不是每次都工作(假设大约 25% 失败)。
这种不稳定的行为是有问题的,我找不到解决方案。 sigslot 库中的信号根据多线程上下文有不同的选项,但它们都不能解决问题。
在尝试 boost 之前,我真的很想找到一个解决方案来继续使用 sigslot,因为它是一个非常简单的库,我只需要在这部分代码中基本使用信号和插槽。我不想为此使用 Qt,因为我更愿意让代码的同一部分不使用 Qt。
任何提示将不胜感激。
更新:出于某种原因,将 sigslot::single_threaded 用作绝望的尝试似乎会产生更好的结果。
signal1<int, single_threaded> Sig1;
我并不是说它正在解决问题,因为它对我来说没有意义。如文档中所述: 单线程 在单线程模式下,库不会尝试保护其内部数据结构 跨线程。因此,对构造函数、析构函数和信号的所有调用至关重要 必须存在于单个线程中。
更新 2:
这是一个 MWE。但结果是相当随机的。有时它完全有效,有时不是全部。我知道这听起来很奇怪,但这就是问题所在。我也尝试了 boost::signals2 而不是 sigslot,但结果完全一样。 boost::signals2::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
}
【问题讨论】:
-
很抱歉没有制作 MWE,我确实在寻找全局答案而不是代码调试(比如“Qt 和 sigslot 不能一起工作”)。由于行为不稳定且上下文非常复杂,我认为不值得举个例子
-
最重要的缺失部分是:没有“the”sigslot 库。这是一个废弃的项目,可以从各种来源进行多个,呃,分解阶段。请添加指向您正在使用的版本的链接。
-
好吧,我不知道这个库。我开始使用是因为我发现只有好的反馈。我正在使用这个版本:sourceforge.net/p/sigslot/patches/3
-
除非所有的插槽都是线程安全的,否则这不可能奏效。具体来说,
std::cout不是线程安全的,因此从多个线程调用它已经是未定义的行为。 -
请注意,您拥有的补丁不是必需的。
QT_NO_KEYWORDS是您需要添加到项目的DEFINES的宏,它可以修复它。您还使用了旧版本的 Visual Studio,这是唯一采用原始 sigslot 代码并且不会抱怨的编译器。原始 sigslot 不是有效的 C++。我将“很快”提供更新@@github.com/KubaO/sigslot
标签: c++ multithreading qt signals-slots