Qt在主线程上运行lambda

Qt run lambda on main thread

本文关键字:运行 lambda 线程 Qt      更新时间:2023-10-16

在我的应用程序中,我有一个工作线程通过文件列表迭代,我试图更新GUI表视图,以指示当前文件是什么。在我的工作线程中,当我启动一个新文件时,我有以下行:

emit runOnGui([this,row](){ui.tblFiles->selectRow(row);});

其中runOnGui是一个信号,通过:

connect(this, &MainWindow::runOnGui, [this](function<void()> action){
    action();
    });

我的理解是action()现在应该在UI线程上运行,但有时,并非总是如此,这对我来说是分段的。反向跟踪看起来像:

#0  0x00007ffff537c28a in ?? () from /usr/lib/libQt5Core.so.5
#1  0x00007ffff537cf23 in ?? () from /usr/lib/libQt5Core.so.5
#2  0x00007ffff537d047 in ?? () from /usr/lib/libQt5Core.so.5
#3  0x00007ffff5376943 in QItemSelection::merge(QItemSelection const&, QFlags<QItemSelectionModel::SelectionFlag>) () from /usr/lib/libQt5Core.so.5
#4  0x00007ffff5379e43 in QItemSelectionModel::select(QItemSelection const&, QFlags<QItemSelectionModel::SelectionFlag>) () from /usr/lib/libQt5Core.so.5
#5  0x00007ffff6d97511 in ?? () from /usr/lib/libQt5Widgets.so.5
#6  0x0000000000465193 in MainWindow::<lambda()>::operator()(void) const (__closure=0x7fffda262710) at <...>/MainWindow.cpp:248
#7  0x00000000004682c8 in std::_Function_handler<void(), MainWindow::pushFiles()::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...) at /usr/include/c++/6.2.1/functional:1740
#8  0x0000000000472722 in std::function<void ()>::operator()() const (this=0x7fffda262710) at /usr/include/c++/6.2.1/functional:2136
#9  0x0000000000463798 in MainWindow::MainWindow(QWidget*)::{lambda(std::function<void ()>)#1}::operator()(std::function<void ()>) const () at <...>/MainWindow.cpp:34
#10 0x0000000000469a32 in QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<std::function<void()> >, void, MainWindow::MainWindow(QWidget*)::<lambda(std::function<void()>)> >::call(MainWindow::<lambda(std::function<void()>)> &, void **) (f=..., arg=0x7fffda2628e0) at /usr/include/qt/QtCore/qobjectdefs_impl.h:501
#11 0x000000000046977b in QtPrivate::Functor<MainWindow::MainWindow(QWidget*)::<lambda(std::function<void()>)>, 1>::call<QtPrivate::List<std::function<void()> >, void>(MainWindow::<lambda(std::function<void()>)> &, void *, void **) (f=..., arg=0x7fffda2628e0) at /usr/include/qt/QtCore/qobjectdefs_impl.h:558
#12 0x0000000000468d8c in QtPrivate::QFunctorSlotObject<MainWindow::MainWindow(QWidget*)::<lambda(std::function<void()>)>, 1, QtPrivate::List<std::function<void()> >, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *) (which=1, this_=0x7cc630, r=0x7fffffffe500, a=0x7fffda2628e0, ret=0x0) at /usr/include/qt/QtCore/qobject_impl.h:198
#13 0x00007ffff53ed85e in QMetaObject::activate(QObject*, int, int, void**) () from /usr/lib/libQt5Core.so.5
#14 0x000000000047a669 in MainWindow::runOnGui(std::function<void ()>) (this=0x7fffffffe500, _t1=...) at <...>/moc_MainWindow.cpp:128
#15 0x0000000000465617 in MainWindow::pushFiles (this=0x7fffffffe500) at <...>/MainWindow.cpp:248
#16 0x0000000000476d14 in std::__invoke_impl<void, void (MainWindow::* const&)(), MainWindow*>(std::__invoke_memfun_deref, void (MainWindow::* const&)(), MainWindow*&&) ( __f=@0xa35080: (void (MainWindow::*)(MainWindow * const)) 0x4651ea <MainWindow::pushFiles()>, __t=<unknown type in <...>/simtool, CU 0x16a5cd, DIE 0x1cbd99>) at /usr/include/c++/6.2.1/functional:235
#17 0x0000000000476ca1 in std::__invoke<void (MainWindow::* const&)(), MainWindow*>(void (MainWindow::* const&)(), MainWindow*&&) ( __fn=@0xa35080: (void (MainWindow::*)(MainWindow * const)) 0x4651ea <MainWindow::pushFiles()>, __args#0=<unknown type in <...>/simtool, CU 0x16a5cd, DIE 0x1cbd99>) at /usr/include/c++/6.2.1/functional:260
#18 0x0000000000476c52 in std::_Mem_fn_base<void (MainWindow::*)(), true>::operator()<MainWindow*>(MainWindow*&&) const (this=0xa35080, __args#0=<unknown type in <...>/simtool, CU 0x16a5cd, DIE 0x1cbd99>) at /usr/include/c++/6.2.1/functional:613
#19 0x0000000000476c1d in std::_Bind_simple<std::_Mem_fn<void (MainWindow::*)()> (MainWindow*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0xa35078) at /usr/include/c++/6.2.1/functional:1400
#20 0x0000000000476b37 in std::_Bind_simple<std::_Mem_fn<void (MainWindow::*)()> (MainWindow*)>::operator()() ( this=0xa35078) at /usr/include/c++/6.2.1/functional:1389
#21 0x0000000000476ad6 in std::thread::_State_impl<std::_Bind_simple<std::_Mem_fn<void (MainWindow::*)()> (MainWindow*)> >::_M_run() (this=0xa35070) at /usr/include/c++/6.2.1/thread:196
#22 0x00007ffff4e6e31f in std::execute_native_thread_routine (__p=0xa35070) at /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:83
#23 0x00007ffff743f454 in start_thread () from /usr/lib/libpthread.so.0
#24 0x00007ffff45e27df in clone () from /usr/lib/libc.so.6

知道为什么会发生分段错误吗?

Misc信息:

  • Qt 5.7
  • Arch Linux 4.7.4
  • gcc 6.2.1

在信号/槽连接中自动跨越线程边界需要一个接收器对象,以便发出代码可以检查当前线程是否等于或不同于接收器的线程。

您可以尝试使用connect变体,它将引用对象作为第三个参数,或者使用QMetaObject::invokeMethod()调用插槽,并显式地声明Qt::QueuedConnection作为连接类型。

QMetaObject::invokeMethod(ui.tblFiles, "selectRow", Qt::QueuedConnection, Q_ARG(int, row));