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
}