【问题标题】:Synchronizing data access in different threads同步不同线程中的数据访问
【发布时间】:2013-11-07 21:37:11
【问题描述】:

我有一个工作线程,它通过 TCP 发送一些数据,从其他几个线程获取这些数据。我需要填充一些数据,上面有一个互斥体,然后调用另一个线程的方法,然后在完成时解锁互斥体,而调用者线程将继续自己的工作。

我首先使用 Qt 实现了这一点,如下所示:

Data globalData;
QMutex mutex;

void requestSend() // several such functions in other threads
{
    mutex.lock(); // we want to change the data
    globalData=fillData();
    invokeMethod(workerClass,"work",Qt::QueuedConnection);
}

void work() // a slot in a class instanced in worker thread
{
    sendData(globalData);
    mutex.unlock(); // data is now available to be changed
}

这看起来很合理,甚至可行,但后来我在 QMutex 文档中找到了这个:

void QMutex::unlock ()

解锁互斥锁。尝试在与锁定的线程不同的线程中解锁互斥锁 这会导致错误。解锁未锁定的互斥锁会导致未定义的行为。

我有两个问题:

  1. 这种限制在不同线程中解锁的原因是什么? (为什么我看不到文档所说的错误?)

  2. 我应该使用什么来代替 QMutex 来实现我想要的? QWaitCondition 会是一个合适的替代品吗?

【问题讨论】:

  • 为什么不使用信号槽直接传递数据,甚至与invokeMethod调用一起传递
  • @ratchetfreak 这将涉及数据复制,而我想避免它。

标签: multithreading qt


【解决方案1】:

互斥锁的目的是确保任何时候只有一个线程可以访问数据。因此,在一个线程中锁定并在另一个线程中解锁相同的互斥体是没有意义的。

如果您发现它有效,那么您现在可能只是幸运,但这并不意味着如果线程时间发生变化它不会给您带来问题。

我不太确定您到底要做什么,但似乎您有各种线程可以写入 globalData 并且一旦您写入它,您希望另一个线程在之前发送数据更多数据写入 globalData。

我的建议是围绕数据的写入创建一个互斥体,然后调用一个信号将数据发送到将发送数据的线程。在不同的线程上,无论如何都会复制数据:-

void requestSend() // several such functions in other threads
{
    QMutexLocker locker(&mutex);
    globalData=fillData();
    emit SendData(globalData); // send signal to the thread which will send the data
}

请注意,QMutexLocker 用于确保释放锁,即使发生异常也是如此。

不要太在意信号和槽中数据的复制;由于implicit sharing,如果您使用它的容器对象,Qt 非常高效,并且只会创建“写入时复制”。即使它必须制作副本以在线程之间传递数据,你也不应该真正担心它,除非你能看到性能问题。

最后,请注意,隐式共享和多线程可以愉快地协同工作,就像 read here 一样。

【讨论】:

  • emit SendData(); 不会在不等待插槽完成的情况下返回吗?在这种情况下,我们将丢失互斥体,它将毫无用处。
  • 应该没问题。当您发出信号时,将数据对象作为参数传递,一切都会好的。隐式共享模型会创建数据的浅拷贝,但如果需要,会发生深拷贝,允许接收线程获取正确的数据,同时另一个线程写入原始容器。
  • 好的,现在你的代码符合你的话:)。因此,在您的示例中,mutex 仅保护数据不被其他线程写入,因为读取不再相关,对吧?
  • 我是这么理解的;其他线程将等到互斥锁解锁后才能继续。
  • 谢谢。事实上,正如我现在所看到的,这种隐式复制是解决这个问题的最干净的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 1970-01-01
相关资源
最近更新 更多