据我所知,函数调用充当编译器屏障,但不是CPU屏障。
这个tutorial说:
“获取锁意味着获取语义,而释放锁意味着释放语义!在两者之间的所有内存操作都包含在一个漂亮的屏障夹心中,防止跨边界的任何不良内存重排序。”
我认为上面的引用是在谈论CPU重排序而不是编译器重排序。
但我不明白互斥锁和解锁如何导致CPU给这些函数提供获取和释放语义。
例如,如果我们有以下C代码:
上述C代码被翻译成以下(伪)汇编指令:
现在,是什么阻止了CPU将
这个tutorial说:
“获取锁意味着获取语义,而释放锁意味着释放语义!在两者之间的所有内存操作都包含在一个漂亮的屏障夹心中,防止跨边界的任何不良内存重排序。”
我认为上面的引用是在谈论CPU重排序而不是编译器重排序。
但我不明白互斥锁和解锁如何导致CPU给这些函数提供获取和释放语义。
例如,如果我们有以下C代码:
pthread_mutex_lock(&lock);
i = 10;
j = 20;
pthread_mutex_unlock(&lock);
上述C代码被翻译成以下(伪)汇编指令:
push the address of lock into the stack
call pthread_mutex_lock()
mov 10 into i
mov 20 into j
push the address of lock into the stack
call pthread_mutex_unlock()
现在,是什么阻止了CPU将
mov 10 into i
和mov 20 into j
重新排序到call pthread_mutex_lock()
上面或call pthread_mutex_unlock()
下面?如果是call
指令阻止了CPU进行重新排序,那么为什么我引用的教程让它看起来像是互斥锁函数阻止了CPU重新排序?为什么我引用的教程没有说任何函数调用都会阻止CPU重新排序?我的问题与x86架构有关。
pthread_mutex_lock()
只是一系列指令,所以再次一般地说,CPU并不知道它是一个特殊的函数,处理器内存重排序是被禁止的。因此,第三次一般地说,没有什么可以阻止CPU将mov 10 into i
重新排序到call pthread_mutex_lock()
之上。因此,自然而然地会问这个问题。现在让我从互斥锁的含义开始回答以下问题... - zzzhhhmov 10 into i
代码被重新排序到call pthread_mutex_lock()
之前时,线程2可能会在那一点上运行关键部分,因为线程1尚未获取互斥锁,这是违反互斥锁含义的。你可以找到很多由于两个线程同时运行关键部分代码而导致灾难的例子。 - zzzhhh