假设我有这个:
go func() {
for range time.Tick(1 * time.Millisecond) {
a, b = b, a
}
}()
其他地方:
i := a // <-- Is this safe?
对于这个问题,i
相对于原始a
或b
的价值并不重要。唯一的问题是阅读a
是否安全。也就是说,a
可能是nil
,部分分配,无效,未定义,......除了有效值之外的任何其他内容吗?
I've tried to make it fail但到目前为止它总是成功(在我的Mac上)。
我无法在The Go Memory Model doc中找到超出此引文的任何具体内容:
读取和写入大于单个机器字的值表现为 以未指定的顺序进行多个机器字大小的操作。
这是否意味着单个机器字写入实际上是原子的?并且,如果是这样,函数指针是否在Go单个机器字操作中写入?
答案 0 :(得分:13)
来自多个goroutine的任何变量的非同步,并发访问,其中至少有一个是写入,The Go Memory Model是未定义的行为。
未定义表示其内容: undefined 。可能是您的程序正常工作,可能会无法正常工作。它可能导致Go运行时提供的内存和类型安全性丢失(参见下面的示例)。它甚至可能会使您的程序崩溃。或者甚至可能导致地球爆炸(概率极小,甚至可能低于1e-40,但仍然......)。
这个未定义在您的情况下意味着是,i
可能是nil
,部分分配,无效,未定义,......除{{1}之外的任何其他内容}或a
。这份清单只是所有可能结果的一小部分。
不要再认为某些数据竞赛是(可能是)良性或无害的。如果无人看管,它们可能是最糟糕的事情的来源。
由于您的代码在一个goroutine中写入变量b
并在另一个goroutine(它试图将其值分配给另一个变量a
)中读取它,因此它是一个数据竞争,因此它不是安全。如果在您的测试中它“正确”工作并不重要。可以将您的代码作为起点,扩展/构建它,并由于您最初的“无害”数据竞争而导致灾难。
作为相关问题,请阅读How safe are Golang maps for concurrent Read/Write operations?和Incorrect synchronization in go lang。
强烈建议阅读Dmitry Vyukov撰写的博文:Benign data races: what could possibly go wrong?
这也是一篇非常有趣的博文,展示了一个以故意数据竞赛打破Go的记忆安全的例子:Golang data races to break memory safety
答案 1 :(得分:3)
就Race condition而言,它并不安全。总之,我对竞争条件的理解是,当有多个异步例程(协同程序,线程,进程,goroutine等)试图访问相同的资源并且至少有一个是写操作时,所以在你的例子中我们有2个goroutines读取和写入类型函数的变量,我认为从并发的角度来看,这些变量在某个地方有一个存储空间,我们正在尝试读取或写入该部分内存。
简短回答:只需使用go run -race
标记go build -race
运行您的示例
或public function _initCustomRoute(){
$router = Zend_Controller_Front::getInstance()->getRouter();
$route = new Zend_Controller_Router_Route(':action', array(
'module' => 'default',
'controller' => 'index',
'action' => 'index'
));
$router->addRoute('default-override', $route);
}
,您会看到检测到的数据竞赛。