没有锁定同时读取函数指针是否安全?

时间:2016-12-31 07:49:33

标签: go concurrency goroutine

假设我有这个:

go func() {
    for range time.Tick(1 * time.Millisecond) {
        a, b = b, a
    }
}()

其他地方:

i := a // <-- Is this safe?

对于这个问题,i相对于原始ab的价值并不重要。唯一的问题是阅读a是否安全。也就是说,a可能是nil,部分分配,无效,未定义,......除了有效值之外的任何其他内容吗?

I've tried to make it fail但到目前为止它总是成功(在我的Mac上)。

我无法在The Go Memory Model doc中找到超出此引文的任何具体内容:

  

读取和写入大于单个机器字的值表现为   以未指定的顺序进行多个机器字大小的操作。

这是否意味着单个机器字写入实际上是原子的?并且,如果是这样,函数指针是否在Go单个机器字操作中写入?

更新:此处a properly synchronized solution

2 个答案:

答案 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); } ,您会看到检测到的数据竞赛