3

考虑这个函数:

void foo(int * p)
{
   // something
}

编译器可以假设没有其他线程会修改 p 指向的值吗?或者它是否必须表现得好像这个值可以随时修改?

void bar(volatile int * p)
{
}

如果没有,volatile关键字是否有帮助?GOTW #69声明volatile关键字通常总是被编译器忽略。

编辑:显然对“编译器假定”这句话有一些误解。让我澄清一下:

  • 如果编译器假设是这样,它可以在第一次读取时将值放入*p寄存器,然后使用它直到 p 超出范围。在那一刻,它应该写入*p那个内存地址的值。
  • 如果编译器不这样认为,每次*p读取时,编译器都应该从内存中获取它的值,因为其他线程可能会修改它。每次*p更改,编译器都应该将其写入内存,以便其他线程可以读取它
4

5 回答 5

5

编译器不能做出这样的假设,程序员也不能。volatile 关键字本身并不能防止并发访问。

于 2012-09-10T19:38:10.650 回答
3

编译器可以并且确实假设没有其他线程会修改 指向的值p,这意味着您必须确保您的代码不依赖于此,或者它具有适当的同步机制以避免竞争条件。换句话说,编译器做出了假设,而这个假设可能是错误的。

volatile关键字在这里几乎没有相关性。

于 2012-09-10T19:38:24.920 回答
2

规则是这样的:如果一个线程写入数据位置的同时另一个线程读取或写入同一位置,则程序存在数据竞争,并且程序的行为未定义。在两行之间读取,编译器假定没有其他线程正在写入您的数据。防止数据竞争是您的工作。而且,不,volatile不影响这一点。

于 2012-09-10T19:56:52.520 回答
1

如果没有, volatile 关键字有帮助吗?

它被编译器忽略(即没有优化)而不是线程。

于 2012-09-10T19:39:52.583 回答
1

每个线程都有自己的参数副本,这些副本代表该线程中发生的调用。'p' 的值只有在事实上它们都指向同一个东西时才会被共享。在另一个线程中分配给“p”不会影响该线程中的“p”,因为它们甚至不是同一个变量。

'p' 指向的是一个完全不同的故事。这只是一个内存区域。如果其他线程可以访问它,那么他们可以访问它并且可以随时写入它。保护像这样共享的东西的唯一方法是使用互斥锁。

于 2012-09-10T19:54:47.920 回答