运行时不执行任何操作的函数有什么用处,即:
void Nothing() {}
Run Code Online (Sandbox Code Playgroud)
请注意,我不是在谈论等待一定时间的函数,例如sleep(),只是需要编译器/解释器给出的时间。
我在Qt的源代码中看到了一些x86程序集:
q_atomic_increment:
movl 4(%esp), %ecx
lock
incl (%ecx)
mov $0,%eax
setne %al
ret
.align 4,0x90
.type q_atomic_increment,@function
.size q_atomic_increment,.-q_atomic_increment
Run Code Online (Sandbox Code Playgroud)
从谷歌搜索,我知道lock指令将导致CPU锁定总线,但我不知道CPU何时释放总线?
关于以上整个代码,我不明白这段代码是如何实现的Add?
我和同事为在x86,x64,Itanium,PowerPC和其他10年历史的服务器CPU上运行的各种平台编写软件.
我们刚刚讨论了pthread_mutex_lock()... pthread_mutex_unlock()等互斥函数本身是否足够,或者受保护变量是否需要是volatile.
int foo::bar()
{
//...
//code which may or may not access _protected.
pthread_mutex_lock(m);
int ret = _protected;
pthread_mutex_unlock(m);
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我担心的是缓存.编译器是否可以在堆栈或寄存器中放置_protected的副本,并在赋值中使用该陈旧值?如果没有,是什么阻止了这种情况发生?这种模式的变化是否易受攻击?
我假设编译器实际上并不理解pthread_mutex_lock()是一个特殊函数,所以我们只是受序列点保护吗?
非常感谢.
更新:好的,我可以看到一个趋势,答案解释了为什么不稳定是坏的.我尊重这些答案,但有关该主题的文章很容易在网上找到.我在网上找不到的,以及我问这个问题的原因,就是我如何保护我没有不稳定.如果上面的代码是正确的,那么缓存问题如何无懈可击?
这样做的pthread_mutex_lock和调用pthread_mutex_unlock函数调用的存储栅栏/屏障指令?或者像compare_and_swap暗示那样的低级指令是否有内存障碍?
假设我有自己的非内联函数LockMutex和UnlockMutex,它们正在使用一些适当的互斥体 - 例如boost - inside.对于LockMutex和UnlockMutex的调用,编译器如何知道不重新排序其他操作?它不可能知道如何在其他编译单元中实现这些功能.
void SomeClass::store(int i)
{
LockMutex(_m);
_field = i; // could the compiler move this around?
UnlockMutex(_m);
}
Run Code Online (Sandbox Code Playgroud)
ps:应该使用类的实例来保存锁以保证解锁.我把它留下来简化示例.
根据https://en.cppreference.com/w/cpp/atomic/memory_order mutex.lock()和mutex.unlock()是获取和释放操作。获取操作使得无法在它前面重新排序后面的指令。并且释放操作使得在它之后无法重新排序之前的指令。这使得以下代码:
[Thread 1]
mutex1.lock();
mutex1.unlock();
mutex2.lock();
mutex2.unlock();
[Thread 2]
mutex2.lock();
mutex2.unlock();
mutex1.lock();
mutex1.unlock();
Run Code Online (Sandbox Code Playgroud)
可以重新排序为以下(可能是死锁)代码:
[Thread 1]
mutex1.lock();
mutex2.lock();
mutex1.unlock();
mutex2.unlock();
[Thread 2]
mutex2.lock();
mutex1.lock();
mutex2.unlock();
mutex1.unlock();
Run Code Online (Sandbox Code Playgroud)
这种重新排序是否可能发生。或者有什么规则阻止它?
在linux代码中,我记得听说mutex_lock()周围有一个完整的内存障碍.我想确定它是否也在sem_xxx附近.
#include <pthread.h>
#include <thread>
int main(){
pthread_mutex_t mut;
if (pthread_mutex_init(&mut, NULL) != 0){
return 0;
}
int a = 0;
auto t1 = std::thread([&](){
for(int c = 0; c<=10000;c++){
pthread_mutex_lock(&mut);
a += 1; //#1 suppose this non-atomic object is protected by the mutex
pthread_mutex_unlock(&mut);
}
});
auto t2 = std::thread([&](){
int r = 0;
for(;;){
pthread_mutex_lock(&mut);
r = a;
std::cout<< a <<std::endl; //#2 suppose this non-atomic object is protected by the mutex
pthread_mutex_unlock(&mut);
if(r>=10000){
return;
}
}
});
t1.join();
t2.join(); …Run Code Online (Sandbox Code Playgroud) 因此,当我们的 C 程序(或其他语言)的函数 (funcA) 调用同一程序中的另一个函数 (funcB) 时,funcA 被认为是非叶函数,因为它调用其他函数。因此,设置了堆栈框架和所有内容,而不是使用 redzone。
然而,比如说在 funcB 中,我们不会调用在程序本身中显式编写的任何函数,但我们确实调用了一两个库函数,例如 fscanf()、fopen() (但我认为这并不重要,只要它是库函数)。那么 funcB 是否会不是叶函数,因为它仍在调用另一个函数?x86 中如何处理库函数?
分析一些 x86 很明显没有发生明显的跳转,但我可以看到它的执行方式类似于,call __isoc99_fscanf@PLT #和call perror@PLT #。