标签: happens-before

如何理解golang内存模型中的通道通信规则?

在学习golang的过程中,当我试图理解内存模型规范中描述的通道通信时,我有点困惑,如下所示:

  1. 通道上的发送在该通道的相应接收完成之前发生.
  2. 关闭通道发生在返回零值的接收之前,因为通道已关闭.
  3. 来自无缓冲通道的接收在该通道上的发送完成之前发生.
  4. 具有容量C的信道上的第k个接收发生在从该信道发送的第k + Cth个完成之前.

前两条规则清晰且易于理解,而我对第三条规则感到困惑,这似乎与其他规则相反......我是否错过了任何关于无缓冲通道的特殊规定?或者我是否正确如果我像下面的规范中的示例那样:

var c = make(chan int)
var a string

func f() {
    a = "hello, world"
    <-c    // A
}
func main() {
    go f()
    c <- 0 // B
    print(a)
}
Run Code Online (Sandbox Code Playgroud)

对于无缓冲通道,发送操作(B)被阻塞,直到接收器准备好接收值(A)?(比如:B开始并且直到A执行才返回)它准确吗?

我在Effective Go规范中找到了以下陈述,但是我的理解仍然存在差异......那么有人可以用简单直接的方式解释这个吗?

接收器始终阻塞,直到有数据要接收.如果通道未缓冲,则发送方将阻塞,直到接收方收到该值.如果通道有缓冲区,则发送方仅阻塞,直到将值复制到缓冲区为止; 如果缓冲区已满,则表示等待某个接收方检索到某个值.

channel memory-model go happens-before

3
推荐指数
1
解决办法
667
查看次数

thread.start 之前发生的所有事情对于调用 start 生成的线程是否可见?

现在 stackoverflow 上已经有很好的答案,但他们没有给我想要的明确答案。

\n\n

说你有方法

\n\n
Dosomething();\n doAnother();\n  int x = 5;\n  Runnable r = new Runnable(){\n     public void run(){\n     int y = x;\n     x = 7;\n     System.out.println(z);}\n   }\n   new Thread(r).start()\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,同时该方法正在运行,并且在调用 thread.start 之前,一些全局非易失性变量 z 从 4 更改为 5。

\n\n

由于 z 发生在 thread.start 之前,程序是否能保证打印 5?

\n\n

另外,如果我们以某种方式谈论它,那么可以肯定地说 thread.start() 永远不能重新排序。

\n\n

就被称为启动的线程而言,这意味着,就好像到该点为止的所有内容都是顺序的。例如说我们有

\n\n
int k = 8;\nnew Thread(() -> {}).start()\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在...从该线程的角度来看,无论首先调用 start 还是 k 被分配 8,都不会产生任何影响。因此可以重新排序,但由于发生在保证之前,这不可能吗?

\n\n

java 规范并没有给出强有力的声明来说明这一点。相反它说

\n\n

当语句调用\xc2\xa0Thread.start()时,与该语句有happens-before关系的每个语句

\n\n

然而 k = 8 并不表示 a …

java concurrency multithreading visibility happens-before

2
推荐指数
1
解决办法
648
查看次数

wait() 和 notify() JMM 语义

我有一个非常特别的问题,我找不到答案。

正如我们所知,在synchronized块的入口处,线程会重新读取其范围内的所有共享(非本地)变量。某些底层架构的示例:如果线程 A 更新 RAM 中的对象状态,线程 B 进入同步块将看到更改。类似的事情发生在退出synchronized块时:线程将其范围内的所有内容刷新到 RAM,以便其他线程可以看到它。这些是基本的 JVM 可见性保证,并且存在发生之前的规则来强制执行它。

但是,从语义上讲,代码使用wait()notify()也执行所有这些操作并不是很清楚:毕竟它没有明确地进入或离开synchronized块。

这些问题是:

  1. JVM 是否确保在wait()入口处对其他线程的更改可见?
  2. JVM 是否确保其他线程在wait()休假时所做更改的可见性?
  3. 该线程是否确保对其他线程的更改可见 notify()

java multithreading synchronized java-memory-model happens-before

1
推荐指数
1
解决办法
67
查看次数

Java 发生在关系之前?

考虑以下代码。

public class Test {
    private boolean running = false;

    public void run() {
        running = true;
    }

    public void test() {
        boolean running1 = running;
        boolean running2 = running;
        System.out.println("running1: " + running1);
        System.out.println("running2: " + running2);
    }
}
Run Code Online (Sandbox Code Playgroud)

线程 A 调用run(),然后另一个线程 B 调用test()并且不应该有任何发生之前的关系。我知道不能保证线程 B 看到线程 A 所做的更改。但是这个程序的输出有没有可能是:

running1: true
running2: false
Run Code Online (Sandbox Code Playgroud)

java concurrency multithreading thread-safety happens-before

1
推荐指数
1
解决办法
65
查看次数

在Java中建立关系

我知道,有两种方法可以在java中建立before-before关系:synchronized块和方法,volatile关键字.(如果我是正确的,它不适用于最终字段).我的问题是:并发包中的原子变量是否相似?可以发生 - 之前由他们建立?

java concurrency multithreading java.util.concurrent happens-before

0
推荐指数
1
解决办法
191
查看次数

go编译器可以重新排序以下代码吗?

最近,我发现一些代码如下所示:

var m map[int]int

func writem() {
    tmpm := make(map[int]int)
    for i := 0; i < 4000000; i++ {
        tmpm[i] = i + 10
    }
    m = tmpm
}

func readm() {
    for k, v := range m {
        _, _ = k, v
    }
}

func main() {
    writem()
    go readm()
    writem()
}
Run Code Online (Sandbox Code Playgroud)

该程序运行良好,但是我认为writem可以通过m = tmpm在for循环之前移动功能主体来重新排序,因为这不会更改此goroutine中的行为。而且这种重新排序将导致concurrent map read and map write问题。正如Go Memory Model所说:

仅当重新排序不会改变语言规范所定义的该goroutine中的行为时,编译器和处理器才可以对单个goroutine中执行的读写进行重新排序。

是的,还是这样编写代码安全吗?

concurrency go happens-before data-race

-1
推荐指数
1
解决办法
72
查看次数