0
#include "boost/smart_ptr/detail/spinlock.hpp"
boost::detail::spinlock lock;
main(){
    std::lock_guard<boost::detail::spinlock> guard(lock);
    while(true)
        {
                i=i+100;
        }
}

机器详情:

CPU:2

在线 CPU(s) 列表:0,1

每个内核的线程数:1

每个插槽的核心数:2

插座:1

在上面的代码中,当我运行时:

First instance => 它占用了 100% 的 cpu(根据 top 命令)

Second instance =>它花费了 97-98%,这两个实例的总和显示大约 195%-197%

Third instance => 通过调整前两个实例的 CPU 消耗,这花费了大约 47-50%,这三个的总和接近 200%。

我的假设是,一旦自旋锁获得 cpu,它就不会被 cpu 抢占(它不会被 cpu 通过调度其他线程来切换,此时将线程(自旋锁定)保持在调度队列中),因此我期待第三个实例失败。但它运行表明前两个进程线程被抢占了。

我在哪里弄错了?

4

1 回答 1

1

我想你误解了自旋锁是什么。它并不比这复杂得多:

class SpinLock {
public:
    void lock() {
        while (is_locked) { /*do nothing*/ }
        // ...MAGIC HAPPENS HERE...
        is_locked = true;
    }

    void unlock() {
        is_locked = false;
        // ...SUBTLE magic happens here...
    }

private:
    bool is_locked = false;
};

MAGIC代码使用特殊机器指令*来确保,如果多个线程同时在while循环中“旋转”,则当其他线程调用该函数时,只有其中一个线程会看到并退出循环。is_locked == falseunlock()

我的假设是,一旦自旋锁获得 CPU...

自旋锁中没有任何东西可以“获取” CPU。它只是CPU 运行的代码,与程序中的任何其他代码没有什么不同。操作系统 (OS) 决定在哪个 CPU 上运行哪个线程以及何时运行,自旋锁所做的任何事情都不会影响这一点。

...它不会被 CPU 抢占。

CPU不会抢占任何东西。CPU 只是执行代码。当 CPU 恰好在运行 OS 代码时,OS 可以选择抢占当前线程。自旋锁对于哪个线程被抢占、何时被抢占或为什么被抢占没有任何影响。

“抢占”意味着操作系统暂停一些正在运行的线程并允许其他一些线程轮流运行。它每秒可能发生 100 次,通常,所涉及的线程都没有意识到它。

自旋锁对抢占没有影响的原因是,它们只是 代码。纯自旋锁不会以任何方式调用操作系统或与操作系统通信。操作系统无法区分计算 pi 位数的线程、平衡银行账户的线程或等待自旋锁的线程。


函数SUBTLE magic中的由用于强制执行 C++内存模型的内存屏障指令组成。这是一个深奥的话题——对于这个答案来说太深奥了。unlock()


* C++原子操作库 为您提供对那些“特殊”机器指令的低级访问。

于 2020-04-28T12:41:02.157 回答