首页 > 解决方案 > 阻塞的互斥锁有多贵?

问题描述

假设我有一个互斥锁,线程 1 锁定了互斥锁。现在,线程 2 尝试获取锁,但它被阻塞了,比如说几秒钟。这个阻塞线程有多贵?可以重新安排正在执行的硬件线程来做一些计算上更昂贵的事情吗?如果是,那么谁检查互斥锁是否被解锁?

编辑:好的,所以我尝试重新制定我想问的内容。

我真的不明白以下是如何工作的。线程 2 被阻塞了,那么线程 2 到底是做什么的呢?从答案看来,它不仅仅是不断检查互斥锁是否被解锁。如果是这种情况,我会认为阻塞线程很昂贵,因为我正在使用我的一个硬件线程来检查某些布尔值是否发生变化。

所以我认为当互斥锁被线程1释放时,线程1通知sheduler并且shedular分配一个硬件线程来执行正在等待的线程2,我是否正确?

标签: c++multithreadinglockingmutex

解决方案


我正在阅读您的问题:

锁定的互斥锁有多贵?

互斥量可以被认为是内存中的整数。试图锁定互斥锁的线程必须读取互斥锁的现有状态,并且可以根据读取的值设置它。

test_and_set( &mutex_value, 0, 1 );   // if mutex_value is 0, set to 1

诀窍是读取和写入(也称为测试和设置)操作都应该是原子的。原子性是通过 CPU 支持实现的。

但是,test-and-set 操作不提供任何阻止/等待的机制。CPU 不知道线程在互斥体上阻塞。操作系统负责通过向用户提供系统调用来管理阻塞。实现因操作系统而异。对于 Linux,您可以考虑 futex 或 pthreads 作为示例。

使用互斥锁的总成本总计为测试和设置操作以及用于实现互斥锁的系统调用。测试和设置操作几乎是恒定的,与其他操作的成本相比微不足道。

如果有多个线程试图获取锁,互斥锁的成本可以归结为以下几点:

    1. Kernel scheduling overhead cost
    2. Context switch overhead cost

内核调度开销

如果一个线程已经获得了互斥锁上的锁,其他线程会发生什么?

其他线程将继续。如果任何其他线程试图锁定已锁定的互斥锁,操作系统将(重新)调度其他线程等待。一旦原始线程解锁互斥锁,内核就会唤醒等待互斥锁的线程之一。

上下文切换开销

用户空间代码应该以这样一种方式设计,即线程应该花费更少的时间尝试锁定互斥锁。如果您有多个线程试图在多个位置获取互斥锁上的锁,则可能会导致灾难,并且性能可能与处理所有请求的单个线程一样差。

可以重新安排正在执行的硬件线程来做一些计算上更昂贵的事情吗?

如果我正确地回答了您的问题,则获得锁的线程可以进行上下文切换,具体取决于调度机制。但是,这本身就是多线程编程的开销。你能提供一个用例来清楚地定义这个问题吗?

谁检查互斥锁是否被解锁?

绝对是操作系统调度程序。注意,它不仅仅是一个盲目的 sleep()。


推荐阅读