作为本科生的一部分,我正在参加一门操作系统课程,遇到了一个令人沮丧的错误,只有在设置-O2/3标志的情况下编译时才会出现。
系统:x86
编译器:GCC
仿真器:Bochs/Qemu
我使用旋转锁(一种TTAS实现(来维护关键部分。
static int
xchange(int*s)
{
int val = LOCKED;
/* Exchanging value at lock address with 1, returns the old value */
asm volatile("xchg (%%eax), %%ebx" : "=b"(val) : "0"(val), "a"(s));
return val;
}
void
TTAS(int *s)
{
/* While lock is locked, do nothing */
while(TRUE){
while(*s == LOCKED){}
/* If lock acquired */
if( xchange(s) == UNLOCKED){
return;
}
}
}
现在,当两个线程处理一个混合了条件等待和锁定的共享变量时,就会出现错误。线程认为他们已经获得了锁,但随后的读取返回了错误的(旧的(值。我尝试包装锁以打印出最后一个"所有者",但这增加了时间,导致同步保持不变。锁的最后一个也是现在的所有者:线程2自己比赛
如果我在获取后打印锁的值。
TTAS(lock <int*>);
print(lock::val);
print(lock::val);
第一次打印"0",第二次打印"1">
如果我用TAS交换TTAS,它似乎有效。
void
TAS(int *s)
{
/* While lock is locked, do nothing */
While( xchange(s) != UNLOCKED){}
}
我无法确定是什么导致了这种行为,希望你们中的一些人能帮助我推理
编辑:更正了exchange 上错误的无效返回
参考下面的评论和Peter Cordes的指导,正确的解决方案是:
#define UNLOCKED 0
#define LOCKED 1
#define TRUE 1
static int
xchg(int volatile *s) {
int val = LOCKED;
asm("xchg %0, %1" : "+m"(*s), "+r"(val)::"memory");
return val;
}
void
TTAS_acquire(int volatile *s) {
while(TRUE){
while(*s == LOCKED){}
if(xchg(s) == UNLOCKED){
return;
}
}
}
void
TTAS_release(int volatile *s) {
asm("":::"memory");
*s = UNLOCKED;
}
编辑:我想我在这一枪上跳枪了!提出的解决方案似乎解决了问题,但这只是症状。我收回这个!还更改了错误的返回值,它从不为空。
第2版:根据Peter Cordes的指导改写答案,还包括发布功能,请参阅评论。