互斥锁定在单独的类上

时间:2015-11-03 17:28:12

标签: c++ multithreading

Mutex的正确用法是什么?我怎么知道它在保护什么?是否会阻止所有线程在锁定期间运行?

例如,我有一个包含对象列表的单例。

NSString *newID = [[NSUUID UUID] UUIDString];

在一个单独的类中,我有一个更新方法。这是在一个单独的线程中运行。

class Foo
{
    // Pretend this is a singleton.
    std::list<Object>* GetObjects() { return &objects; }
    void Reset() { for ( auto iter = objects.begin(); iter != objects.end(); ++iter ) { delete *iter; } }
    std::list<Object> objects;
};

我的问题是我想在Foo上调用Reset(),并删除所有对象。但我的Bar类正在更新所有这些对象。因此,如果它处于更新方法的中间,它可能正在尝试修改已删除的对象。

如何防止这种情况?

我可以在重置功能中创建一个Mutex并在删除之前将其锁定并在之后将其解锁吗?像这样:

class Bar
{
    void Update()
    {
        std::list<Object>* objects Foo.GetObjects(); 
        for(auto iter = objects.begin(); iter != objects .end(); ++iter )
            iter->SetTransform(50,50,50);
    }
};

这是否让其他班级知道这些资源被锁定了?我不确定互斥锁如何知道要保护的信息。它是如何知道它需要锁定单例类中的列表。

顺便说一下,这是所有伪代码,因此存在语法错误和缺少信息。

2 个答案:

答案 0 :(得分:3)

简单来说,互斥锁是一种锁定机制。

说,你有一个资源,在你的情况下list<object> objects; 现在,如果多个线程同时在此列表上运行,那么这些操作的结果可能是意外的。

所以,基本上互斥体为我们提供了一种机制,可以确保一次只有一个线程在受保护资源上运行。

实现:

在Linux内核中,线程由task_struct对象建模。互斥实现如下:

struct mutex {
  /* 1: unlocked, 0: locked, negative: locked, possible waiters */
  atomic_t                count;
  spinlock_t              wait_lock;
  struct list_head        wait_list;
 #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
  struct task_struct      *owner;
 #endif
}

因此,尝试锁定互斥锁的第一个线程变为owner,其他所有人都被添加到该互斥锁的wait_list

一旦所有者释放它,wait_list的下一个任务将获得下一次机会。

请注意

  

如果是互斥锁,无论谁锁定它都必须解锁它,

否则其他人将永远被锁定,也称为 dreadlock

答案 1 :(得分:2)

  

Mutex的正确用法是什么?

同步对共享资源的访问。

  

我怎么知道它在保护什么?

通过阅读代码。获取锁定时访问的是受保护的内容。

  

是否会阻止所有线程在锁定期间运行?

没有。只有等待Mutex的人才会“停止”。如果某个其他线程已经锁定,则在您调用Lock()时线程将等待。它将一直等到有锁定调用{​​{1}}的人。如果没有人拥有锁,则调用Unlock()的线程获取它并且不等待。如果你有一个锁,那么多个线程可能正在等待,并且在解锁时没有定义的是谁获得它。请参阅特定框架的文档。

  

如何防止这种情况?我可以在重置功能中创建一个Mutex并在删除之前将其锁定并在之后将其解锁吗?

如果您获取并释放对该共享资源的访问权限,则可以阻止多个线程同时访问共享资源。所以,是的,您可以锁定和解锁重置代码,但是您需要在访问共享资源的所有位置执行此操作。

在这种情况下,Lock()是您的共享资源。如果您在删除objects内容的位置获得锁定,则还必须在您正在使用它的位置获取锁定。由于您通过objects提供引用,因此您还需要具有以下权限的调用方,以实现通过此互斥锁同步访问权限。

另一种方案是摆脱GetObjects()并使用其他方法,例如GetObjects(),获取/设置/操作锁内的数据,从不实际给出原始引用Object *get(int index)

  

这是否让其他班级知道这些资源被锁定了?我不确定互斥锁如何知道要保护哪些信息。

没有。 Mutex什么都不知道。您必须在代码上强加适当的语义,方法是将其记录给调用者,或者通过知道获取Mutex的对象来彻底访问共享资源。