【问题标题】:Do spinlocks guarantee context switching when compared to mutexes与互斥锁相比,自旋锁能保证上下文切换吗
【发布时间】:2020-06-09 22:21:46
【问题描述】:

考虑下面的代码sn-p

int index = 0;
av::utils::Lock lock(av::utils::Lock::EStrategy::eMutex); // Uses a mutex or a spin lock based on specified strategy.

void fun()
{
    for (int i = 0; i < 100; ++i)
    {
        lock.aquire();
        ++index;
        std::cout << "thread "  << std::this_thread::get_id() << " index = " << index << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        lock.release();
    }
}

int main()
{
    std::thread t1(fun);
    std::thread t2(fun);

    t1.join();
    t2.join();
}

我使用用于同步的互斥锁得到的输出是第一个线程 1 完全执行,然后是线程 2。 在使用自旋锁(使用 std::atomic_flag 实现)时,我得到了交错的线程之间的执行顺序(线程 1 的一次迭代,然后是线程 2 的另一次迭代)。后一种情况的发生与我在执行迭代时添加的延迟无关。

我了解互斥锁只保证互斥而不保证执行顺序。我的问题是,如果我想要一个执行顺序,使得两个线程以交错方式执行,是否使用自旋锁是推荐的策略?

【问题讨论】:

  • 如果你想强制交错执行,你需要让每个线程等待轮到它,而不是竞争自旋锁。
  • 您可以拥有两个轮流使用的互斥锁。或者你可以有一个条件变量来保护另一个变量,说明轮到谁了。
  • 我看不出这样做的目的。为什么?
  • 请考虑不要问是/否问题。答案显然是“不”,因为 C++ 规范中没有任何内容需要这种行为,而且您不能对底层硬件和操作系统现在和永远运行的方式做出任何假设。
  • 我不太明白运行线程互斥的动机。当我引入线程时,我想同时运行它们——尽可能少地同步,也就是通信。当然,通常不同步就无法完全完成。例如对于生产者-消费者或共享资源。但是,要按意图交错运行线程......在这种情况下,我会考虑如果没有线程的所有额外麻烦,这是否不能做得更好。 (对不起,只是我的两分钱......)

标签: c++ multithreading mutex spinlock


【解决方案1】:

我使用互斥锁得到的输出......是第一个线程 1 [贯穿整个循环],然后是线程 2。

这是因为你的循环如何使用锁:循环体做的最后一件事就是解锁锁。它在下一次迭代开始时所做的下一件事就是再次锁定锁。

另一个线程可以被阻塞,有效地休眠,等待互斥体。当你的线程 1 释放锁时,操作系统调度程序可能仍在运行它的算法,试图找出如何响应它,当线程 1 再次出现并锁定锁时。

这就像一场锁定互斥锁的竞赛,枪响时线程 1 在起跑线上,而线程 2 则坐在板凳上系鞋带。

使用自旋锁时...交错的线程之间的执行顺序

那是因为“阻塞”线程并没有真正被阻塞。它在等待时仍然在不同的处理器上积极运行。当第一个线程释放它时,它更有可能赢得锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-16
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多