尝试通过 "lock xchg" 程序集实现自旋锁

Trying to implement a spin-lock via "lock xchg" assembly

基本上,我试图在两个线程中 运行 void spinlock_counter(int) 并且计数应该是 2000(参数不执行任何操作我只是太懒了)。然而,我在关键区域做了一个断点,即“count++”并打印了“flag”,标志是“GO”(如果一切正常,标志应该是“BLOCK”)。 不明白为什么这不起作用。

感谢您的回答!

代码:

int xchg(volatile int *addr, int newval){
    int result;
    asm volatile("lock xchg %0, %1"
    :"+m"(addr),
    "=a"(result)
    :"1"(newval)
    :"cc");
    return result;
}
#define GO 0
#define BLOCK 1
int flag = GO;

void lock(int *addr){
    int note = BLOCK;
    while(!xchg(addr, note));
}

void unlock_spin(int *addr){
    int note = GO;
    xchg(addr, note);
}

void spinlock_counter(int a){
    while(1) {
        lock(&flag);
        count++;
        unlock_spin(&flag);
        }
        printf("%d\n", count);
}

您的 while 循环(在 lock() 中)的条件是倒退的。

结果是 lock() 实际上什么也没做。如果另一个线程已经获得了锁,它根本不会旋转,如果锁是 GO 它会旋转一次(在第一次迭代时将锁设置为 BLOCK 以便旋转停止第二次迭代)。

我建议编写代码以 clearer/less confusing/less 容易出错的方式(并且永远不要依赖 C 中 true/false 的值)来描述您的意图,以便这些类型错误被阻止。例如:

void lock(int *addr){
    int note = BLOCK;
    while(xchg(addr, note) != GO);
}

However I made a breakpoint in the critical zone i.e. "count++" and printed "flag", the flag is "GO"

这可能是一个单独的错误(尽管第一个错误可能会导致另一个线程在您的线程锁定后解锁,但它不容易重现)。具体来说;没有什么能阻止编译器 re-ordering 您的代码,您需要某种障碍来阻止编译器将您的代码转换为 lock(&flag); unlock_spin(&flag); 然后 count++; 的等价物。将内联程序集的破坏列表更改为 "cc, memory" 应该可以防止编译器对函数重新排序。