C++ 独立类上的互斥锁

C++ 独立类上的互斥锁,c++,multithreading,C++,Multithreading,互斥锁的正确用法是什么?我怎么知道它在保护什么?它是否会在锁定期间停止所有线程的运行 例如,我有一个包含对象列表的单例 class Foo { // Pretend this is a singleton. std::list<Object>* GetObjects() { return &objects; } void Reset() { for ( auto iter = objects.begin(); iter != objects.end()

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

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

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;
};
这是否让其他类知道这些资源已锁定?我不确定互斥体如何知道要保护哪些信息。它如何知道需要在singleton类中锁定列表

顺便说一句,这是所有的伪代码,所以有语法错误和丢失的信息

互斥锁的正确用法是什么

同步对共享资源的访问

我怎么知道它在保护什么

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

它是否会在锁定期间停止所有线程的运行

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

我如何防止这种情况?我可以在reset函数中创建一个互斥体并在删除前锁定它,然后在删除后解锁它吗

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

在这种情况下,
对象
是您的共享资源。如果在删除
对象内容的位置获取锁,则还必须在使用锁的位置获取锁。由于您通过
GetObjects()
发出了一个引用,因此您还需要让其调用者意识到需要通过这个互斥来同步访问

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

这是否让其他类知道这些资源已锁定?我不确定互斥体如何知道要保护哪些信息


不,互斥锁什么都不知道。您必须对代码施加适当的语义,要么为调用方记录代码,要么通过知道获取互斥体的对象取消对共享资源的所有访问。

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

比如说,你有一个资源,在你的例子中
列出对象
现在,如果多个线程最终同时在此列表上运行,那么这些操作的结果可能是意外的

因此,基本上互斥为我们提供了一种机制,确保每次只有一个线程在受保护的资源上运行

实施:

在Linux内核中,线程由
task\u 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
}
因此,尝试锁定互斥体的第一个线程成为
所有者
,其他所有线程都被添加到该互斥体的
等待列表

一旦所有者释放它,等待列表中的下一个任务将获得下一次机会

注意

如果是互斥锁,锁定它的人必须解锁它


否则,其他所有人都将被永久锁定,也称为可怕的锁定。

您是否正在寻找类似的东西=它必须是同一个互斥锁吗?或者它可以是reset()和update()的独立互斥体。它必须是同一个互斥体。现在的问题是,您获取锁以执行重置操作,但没有其他人等待释放锁。通过在访问对象之前锁定互斥体,如果重置操作正在运行,则另一个线程将不得不等待重置完成,然后Lock()返回并在第一个线程上继续执行。如果创建两个不同的mutex,那么本质上也会有相同的问题,因为如果有人锁定了mutexB,mutexA.Lock()将不会等待。
 void Reset()
 {
     Mutex mutex; mutex.Lock()
     for ( auto iter = objects.begin(); iter != objects.end(); ++iter )
         delete *iter;
     mutex.Unlock();
}
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
}