gpt4 book ai didi

c++ - QThread:从不同线程修改变量的安全方法?

转载 作者:行者123 更新时间:2023-11-30 01:57:15 35 4
gpt4 key购买 nike

我是 QThread 和多线程的新手,所以我不确定我是否做对了。该程序到目前为止还没有崩溃,但我想检查我是否正确执行。我有一些代码如下(MyThreadClass 继承自 QThread):

std::vector<MyThreadClass* > workThreads;
for(int i=0;i<Solutions.size();i++)
{
workThreads.push_back(new MyThreadClass(Solutions[i]));
}
for(int i=0;i<workThreads.size();i++)
{
connect(workThreads[i], SIGNAL(finished()), this, SLOT(onFinished()));
workThreads[i]->start();
}

bool finished = false;
while(!finished)
{
if(m_finishedThread==workThreads.size())
finished=true;

this->msleep(10);
}

onFinished函数给出如下:

void MyClass::onFinished()
{
++m_finishedThread;
}

因此您可以看到 while 循环正在等待所有线程完成并更新 m_finishedThread 变量。这是一种安全的方法吗?如果所有线程都完成了它们的工作并尝试“连接”到 onFinished() 函数,是否会导致问题?

最佳答案

那是安全的。诀窍在于您将在 QThread 子类和 this 之间建立的连接将是一个排队连接。这是因为发出信号 finished (*) 的线程与 this(接收方)所在的线程不同。

排队连接是通过事件发布实现的。一个特殊的事件被发布到线程 this 所在的事件队列中;该事件的处理正在调用您的插槽。所以,你的插槽只会被访问

  1. 依次
  2. 仅来自一个线程:this 所在的线程

这显然是线程安全的。

顺便问一下,那是你的真实代码吗?你可以做同样的事情

for (int i = 0; i < numThreads; ++i) 
threads[i]->wait();

(*) 我说的是发出信号的线程,而不是发出信号的对象的亲和性。特别是,您的 QThread 子类对象很可能与 this 处于同一个线程中!

问题在哪里?发出 finished 的线程不是那些对象(和 this)所在的线程——是由这些对象管理的线程。


附录 (2):this是实现信号发射的代码。如您所见,检查是针对当前运行的线程接收方所在的线程。发件人所在的线程未被考虑在内,因此您不需要需要执行thread->moveToThread(thread)之类的操作来建立排队连接。

当前运行的线程怎么可能与发送者所在的线程不同?因为这正是 QThread 所做的:QThread 对象存在于一个线程中,它管理的线程(并发出 finished()!)是另一个线程:

// runs in the MANAGED thread; lives in any thread
void QThread::run_in_another_thread() {
run(); // user-supplied implementation
emit finished();
}

Addendun to the addendum:但是,您是否依赖未记录的知识,即 finished 是从另一个线程发出的?不就是靠实现吗?

答案是。只有一个其他选择:finished() 作为收割/清理处理的一部分被发出,来自 QThread 对象正在离开的事件循环。也就是说,this 所在的同一线程。

它不能来自其他任何地方——如果我们正在运行用户代码,我们就不会运行任何其他东西(记住一个线程不能运行两个 不同的东西)。

这意味着:

  1. 您在 this 所在的线程中有一个正在运行的事件循环。在任何情况下您都需要它。
  2. 调用将是“直接的”(即直接调用),因为发出信号的线程与 this 所在的线程相同。所以,我们只是调用一个函数 在同一线程内;根据定义,这是线程安全的。

因此,这绝对不会改变我们处理此问题的方式。它需要 this 中的事件事件循环,仅此而已。


附录:我应该更好地阅读代码。这不会改变我上面所说的,但是:

bool finished = false;
while(!finished)
{
if(m_finishedThread==workThreads.size())
finished=true;

this->msleep(10);
}

这里的这个循环永远不会返回到事件循环。这意味着永远不会调用您的插槽,因为永远不会处理元调用事件。请使用 QTimer 或偷偷调用一些 QCoreApplication::processEvents 而不是这种循环!

关于c++ - QThread:从不同线程修改变量的安全方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18953713/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com