【问题标题】:Why do locks work?为什么锁会起作用?
【发布时间】:2009-01-17 05:21:47
【问题描述】:

如果锁确保一次只有一个线程访问锁定的数据,那么什么控制对锁定函数的访问?

我认为boost::mutex::scoped_lock 应该在我的每个函数的开头,这样局部变量就不会被另一个线程意外修改,对吗?如果两个线程试图在非常接近的时间获取锁怎么办?锁内部使用的局部变量不会被其他线程破坏吗?

我的问题不是特定于提升的,但除非你推荐另一个,否则我可能会使用它。

【问题讨论】:

    标签: c++ multithreading boost locking mutex


    【解决方案1】:

    你是对的,在实现锁时,你需要某种方式来保证两个进程不会同时获得锁。要做到这一点,您需要使用原子指令——它可以保证在不中断的情况下完成。一个这样的指令是test-and-set,该操作将获取布尔变量的状态,将其设置为 true,然后返回之前检索到的状态。

    这样做的目的是让您可以编写代码,不断测试它是否可以获得锁。假设 x 是线程之间的共享变量:

    while(testandset(x));
    // ...
    // critical section
    // this code can only be executed by once thread at a time
    // ...
    x = 0; // set x to 0, allow another process into critical section
    

    由于其他线程不断地测试锁,直到它们进入临界区,这是保证互斥的一种非常低效的方法。但是,使用这个简单的概念,您可以构建更复杂的控制结构,例如更高效的信号量(因为进程没有循环,它们正在休眠)

    【讨论】:

    • 另一个这样的原子指令(可能是最重要的)是en.wikipedia.org/wiki/Compare_and_swap
    • 请注意,答案是关于自旋锁,它可以在用户代码中实现。具有阻塞线程睡眠的锁通常(总是?)使用操作系统原语实现。 Boost 只是为它们提供了一个统一的接口。
    • 你说得对,我应该做出这样的区分。您也可以拥有操作系统级别的自旋锁,但这不是一个好主意。
    【解决方案2】:

    您只需拥有对共享数据的独占访问权限。除非它们是静态的或在堆上,否则函数内部的局部变量对于不同的线程会有不同的实例,无需担心。但是共享数据(例如通过指针访问的数据)应该首先被锁定。

    至于锁的工作方式,它们经过精心设计以防止竞争条件,并且通常具有硬件级别的支持以保证原子性。 IE,有一些机器语言结构保证是原子的。信号量(和互斥体)可以通过这些实现。

    【讨论】:

    • 谢谢我试图找出函数是否为每个线程都有一个单独的实例。但是您能否提供一个链接,指向您从中获取此信息的来源?
    • 我没有函数变量的来源,抱歉。但愿我做了,可惜我没有。其余部分来自 semaphore Wikipedia 文章。
    • 别介意搜索线程分离堆栈发现这个:msdn.microsoft.com/en-us/library/ms686774(VS.85).aspx
    【解决方案3】:

    最简单的解释是,锁在下面,是基于保证是原子的并且不会在线程之间发生冲突的硬件指令。

    函数中的普通局部变量已经特定于单个线程。只有静态、全局或其他可以被多个线程同时访问的数据需要锁来保护它。

    【讨论】:

      【解决方案4】:

      操作锁的机制控制对它的访问。

      任何锁定原语都需要能够在处理器之间传达更改,因此它通常在总线操作之上实现,即读取和写入内存。它还需要被构造成两个线程试图声明它不会破坏它的状态。这并不容易,但您通常可以相信任何操作系统实现的锁都不会被多个线程破坏。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-31
        • 1970-01-01
        • 1970-01-01
        • 2014-04-20
        • 2021-12-20
        • 2015-06-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多