我的教授给出了标准Dekker算法的代码,我需要通过实现我们自己的算法来测试NachOS。但我在教授的代码中发现了一个有希望的错误。以下是他为我们提供的Dekker代码的片段:
void DekkerEntry (int *flag, int id, int *turn)
{
flag[id] = 1;
while (flag[1-id]) {
if ((*turn) == (1-id)) {
flag[id] = 0;
while ((*turn) == (1-id)); // mark this while loop
flag[id] = 1;
}
}
}
还有其他与共享内存实现相关的测试,我们的代码运行良好。但是这个进入无限循环。但令我惊讶的是,如果我将标记的while循环更改为只包含一个print语句,它就不会进入无限循环并给出正确的答案!
while ((*turn) == (1-id)){syscall_wrapper_PrintString("hello");}
我认为错误不是将volatile
类型作为turn
并将其作为指针传递,认为其更改将反映在while循环中。根据我的智能编译器没有检查该条件,因为while循环是emtpy,并使用预先存储的turn
的地址值。
但是指针也有这个问题吗?我知道简单变量在while循环中确实存在这个问题,因为编译器可能认为它们的值在循环中没有变化。我很困惑为什么只添加一个print语句算法正常工作,否则不行。我在想吗?很想知道你对此有何看法。
提前致谢。
答案 0 :(得分:1)
volatile
关键字对C ++中的多线程代码没有保证的影响。相反,您需要某种方法在turn
上执行具有内存可见性保证的操作。在您的特定平台上,可能是volatile
关键字。但是既然你没有指定你正在使用的平台的线程标准,我们就无从知晓。如果它只是C ++线程,那么volatile
没有任何帮助,您需要通过原子使用C ++的内存可见性功能。
答案 1 :(得分:0)
在与我的教授亲自协商后,我确信我身边有一些实施问题。请注意,对于手头的问题,将始终检查指针地址值的类似volatile变量(内存可见性在循环中的变化)。因此,while循环条件中的指针绝对没有问题。
了解实际问题:
实际问题是我错误地运行算法仅用于非抢占式上下文切换。当我切换到先发制人的上下文切换时,我得到了它的工作。非抢占式代码的工作(通过添加print语句询问)是I / O操作,因此它只是在非先发制人的上下文切换上切换出来,允许将循环变量更改为在一定程度上但最终陷入僵局。