Qt对象 - 我是否过度使用QMutexLocker?

时间:2010-11-14 20:48:32

标签: multithreading qt

我有一个由GUI线程和网络线程使用的Qt对象。它看起来像:

QString User::Username()
{
    QMutexLocker locker(&mutex);
    return username;
}

void User::SetUsername(const QString &newUsername)
{
    QMutexLocker locker(&mutex);
    username = newUsername;
}

QString User::Password()
{
    QMutexLocker locker(&mutex);
    return password;
}
...

GUI和网络线程都可以使用该对象(例如,在屏幕上显示用户名,并获取通过网络发送的用户名)。

我担心出了问题,因为对象中的每个方法都有一个QMutexLocker行,以使其线程安全。

以这种方式使用QMutexLocker是否可以接受,或者代码结构严重?

3 个答案:

答案 0 :(得分:3)

您应该分别使用QReadWriteLockQReadLockerQWriteLocker。因此,如果只有读取线程,则不会锁定任何线程。

如果该类的某些字段被非常频繁地更改,并且不会更改该类的任何其他状态,则可能需要为其提供自己的专用锁。

答案 1 :(得分:1)

我认为你可能会以错误的方式处理事情。序列化每个方法调用将“排序”工作,但它不能可靠地处理添加或删除User对象等操作。例如,如果主线程删除了User对象,则网络线程小心锁定互斥锁无关紧要,因为在互斥锁操作返回后,网络线程将尝试访问(现已删除)用户对象,并尝试读取或写入释放的内存将导致您的应用程序崩溃(或者更糟糕的是,有时神秘地做错误的事情)。

这是一个更好的方法(假设User对象相当小):而不是让网络线程和I / O线程共享相同的User对象,并尝试序列化对象的所有访问方法级别,您最好将每个User对象的单独副本提供给I / O线程。然后,当一个线程更改其User对象的本地副本时,它应该向包含更新对象的副本的另一个线程发送消息,并且当另一个线程接收到该消息时,它可以更新其本地副本以再次匹配。这样,每个线程都拥有对其自己的本地User对象集的独占读/写访问权限,并且可以在不进行任何锁定的情况下读/写它们。这也允许每个线程随意添加或删除对象(只要它之后向另一个线程发送更新消息,所以另一个线程将跟随)。

答案 2 :(得分:0)

我认为更好更清洁的方法是拥有一个“安全部分”

updateUser( User ) {

  User.acquireLock()
  User.SetUsername(newUsername)
  User.Password()
  < more operations here >
  User.releaseLock()

}

这样做的好处是你只能锁定一次互斥锁(这是一项昂贵的操作)。