并发访问无锁变量

时间:2018-06-20 08:06:44

标签: go concurrency memory-barriers

我为一个问题所困扰,

  

如果只有一个线程写入变量,而另一个线程只是读取变量,我们应该添加锁吗?

所以我写了这样的代码进行测试

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var lock sync.RWMutex
var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

即使经过一秒钟,结果仍保持打印i am here 0。我对内存屏障或cpu缓存有所了解。但是怎么会这么长时间缓存呢?我认为一段时间后,它应该读取我已经更改的变量。

请高手或计算机系统的任何人可以帮助回答?


更新:我知道这样更新变量是错误的方法,我想知道为什么在cpu /内存视图中未定义它。

3 个答案:

答案 0 :(得分:4)

您有一场数据竞赛。因此,结果是不确定的。

search.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence cs, int start, int before, int count) {
        // TODO Auto-generated method stub
        int textlength = cs.length();

        String text = cs.toLowerCase(Locale.getDefault());
        adapter.filter(text);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
                                  int after) {
        // TODO Auto-generated method stub

    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub

    }
});

输出:

package main

import (
    "fmt"
    "runtime"
    "sync"
    "time"
)

var lock sync.RWMutex
var i = 0

func main() {
    runtime.GOMAXPROCS(2)
    go func() {
        for {
            fmt.Println("i am here", i)
            time.Sleep(time.Second)
        }
    }()
    for {
        i += 1
    }
}

参考文献:

Data Race Detector

Benign Data Races: What Could Possibly Go Wrong?

答案 1 :(得分:1)

  

如果只有一个线程写入变量,而另一个线程只是读取变量,我们应该添加锁吗?

是的。总是。这里没有争论。

您的测试代码无法证明或拒绝任何行为,因为其行为未定义。

答案 2 :(得分:0)

最后,我找到了这个答案,我知道通过数据竞赛,您将获得不确定的行为,但是我想知道为什么它目前的行为如此。

此快照代码是因为编译器仅删除添加功能,而从不添加。

所以我们有一个教训,如果你写一个不确定的行为,你可能会得到一个月亮--

编译器会将您的代码视为垃圾,它没有任何价值。