C 地址值更改不会反映在while循环中

C 地址值更改不会反映在while循环中,c,algorithm,synchronization,C,Algorithm,Synchronization,我的教授给了我标准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 ((

我的教授给了我标准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循环中确实存在这个问题,因为在while循环中,编译器可能会假定它们的值在循环中没有改变。我很困惑,为什么只添加一个print语句,算法就能正常工作,否则就不行了。我想得对吗?我很想知道你对此有何看法


>

< P> >代码>易失性/代码>关键字对C++中的多线程代码没有保证作用。相反,您需要某种方法来对具有内存可见性保证的
turn
执行操作。在您的特定平台上,这可能是
volatile
关键字。但由于您没有指定所使用的平台的线程标准,所以我们无法知道。如果只是C++线程,那么<>代码> Value没有帮助,你需要使用原子的C++内存可见性特征。

< P>在和我的教授协商之后,我确信我身边有一些实现问题。请注意,指针地址值将始终与当前问题的易失性变量一样进行检查(循环中的内存可见性更改)。因此,while循环条件下的指针绝对没有问题

要了解实际问题,请执行以下操作:


实际的问题是,我只是错误地为非抢占式上下文切换运行了算法。当我也切换到先发制人的上下文切换时,我让它工作起来了。非抢占式代码(通过添加print语句提出问题)的工作原理是,它是I/O操作,因此只能在非抢占式上下文开关上切换,该开关允许在一定程度上更改循环变量,但最终会挂起死锁

while((*turn)==(1-id))如果条件为
true
,则此选项将永远循环。请注意结尾的分号。@PaulMcKenzie这是一个繁忙的等待。这是非常糟糕的,原因很多,但这就是目的。顺便说一句,原因是为什么没有人应该在任何实际的计算机上甚至像这样远程地使用代码,考虑线程是否执行那个繁忙的等待和它正在等待的线程共享一个物理核。繁忙的等待将垄断核心资源,并减慢它正在等待的线程的速度。此外,考虑到繁忙等待循环最终结束时的可怕错误预测分支惩罚——在最坏的可能时间减慢你的爬行速度。@ PulcMcKeZie你能详细说明你的观点吗?@ Akas:这个逻辑的问题是C++不支持在<代码> int 值上的忙等待。您需要一个
std::atomic
。它是C线程。我们正在实现NachOS,这意味着它们是用户线程。@Akash我对NachOS上的线程还不够熟悉,无法对该平台上的线程语义
volatile
做出有用的评论。但是,如果平台线程文档说您可以依靠
volatile
实现这一目的,那么您可以。“如果不是,那么不是。”Akase:如果是C,请不要使用C++标签。请注意,指针地址值将总是与易失性变量一样检查。因此,在循环条件下指针绝对没有问题。“如果这是正确的,那就是NACHOS平台的事情。对于C或C++来说,这绝对不是真的。当然是“大卫·施瓦茨”。更具体地说,我在讨论循环中的条件,这些条件可能不是内存可见的,但是在C、C++中指针的情况下。玉米片是用C实现的。我已经编辑了答案。谢谢你指出这一点。一般来说,它不是真的,它们不是C或C++中指针的情况。如果这在玉米片中是真的,那是因为玉米片特别这么说。C或C++一般不提供内存可见性,而不是通过指针来保证。这对我来说是有效的。那么,您的意思是,它取决于编译器何时查看更改,以及何时忽略指针,就像普通变量一样?你能提供一个解释或反例吗?@Akash:问题是编译器可能会注意到循环中没有任何东西可以更改指向的变量。您错误的假设是其他线程可能会更改该值,但C需要线程同步。看到线程同步的编译器知道指向的变量可以更改。