gpt4 book ai didi

java - 并发:缓存一致性问题还是编译器优化?

转载 作者:行者123 更新时间:2023-11-29 09:49:18 25 4
gpt4 key购买 nike

据我了解,如果硬件支持多处理器系统上的高速缓存一致性,那么对共享变量的写入将对在其他处理器上运行的线程可见。为了测试这个,我用 Java 和 pThreads 写了一个简单的程序来测试这个

public class mainTest {

public static int i=1, j = 0;
public static void main(String[] args) {

/*
* Thread1: Sleeps for 30ms and then sets i to 1
*/
(new Thread(){
public void run(){
synchronized (this) {
try{
Thread.sleep(30);
System.out.println("Thread1: j=" + mainTest.j);
mainTest.i=0;
}catch(Exception e){
throw new RuntimeException("Thread1 Error");
}
}
}
}).start();

/*
* Thread2: Loops until i=1 and then exits.
*/
(new Thread(){
public void run(){
synchronized (this) {
while(mainTest.i==1){
//System.out.println("Thread2: i = " + i); Comment1
mainTest.j++;
}
System.out.println("\nThread2: i!=1, j=" + j);
}
}
}).start();

/*
* Sleep the main thread for 30 seconds, instead of using join.
*/
Thread.sleep(30000);
}
}




/* pThreads */

#include<stdio.h>
#include<pthread.h>
#include<assert.h>
#include<time.h>

int i = 1, j = 0;

void * threadFunc1(void * args) {
sleep(1);
printf("Thread1: j = %d\n",j);
i = 0;
}

void * threadFunc2(void * args) {
while(i == 1) {
//printf("Thread2: i = %d\n", i);
j++;
}
}

int main() {
pthread_t t1, t2;
int res;
printf("Main: creating threads\n");

res = pthread_create(&t1, NULL, threadFunc1, "Thread1"); assert(res==0);
res = pthread_create(&t2, NULL, threadFunc2, "Thread2"); assert(res==0);

res = pthread_join(t1,NULL); assert(res==0);
res = pthread_join(t2,NULL); assert(res==0);

printf("i = %d\n", i);
printf("Main: End\n");
return 0;
}

我注意到 pThread 程序总是结束。 (我测试了线程 1 的不同 sleep 时间)。然而,Java 程序只结束了很少几次;大多数时候不会结束。如果我取消注释 java 程序中的 Comment1,那么它会一直结束。此外,如果我使用 volatile,那么它在所有情况下都对 java 结束。

所以我的困惑是,

  1. 如果缓存一致性是在硬件中完成的,那么“i=0”应该对其他线程可见,除非编译器优化了代码。但是如果编译器优化了代码,那么我不明白为什么线程有时会结束而有时不会。另外添加 System.out.println 似乎会改变行为。

  2. 谁能看到导致此行为的 Java 编译器优化(不是由 C 编译器完成)?

  3. 编译器是否需要做一些额外的事情来获得缓存一致性,即使硬件已经支持它? (如启用/禁用)

  4. 我应该默认对所有共享变量使用 Volatile 吗?

我错过了什么吗?欢迎任何其他评论。

最佳答案

if cache coherence is done in hardware, then 'i=0' should be visible to other threads unless compiler optimized the code. But if compiler optimized the code, then I don't understand why the thread ends sometimes and doesn't sometimes. Also adding a System.out.println seems to change the behavior.

注意:javac 几乎没有进行任何优化,所以不要考虑静态优化。

您正在锁定与您正在修改的对象无关的不同对象。由于您正在修改的字段不是 volatile,因此 JVM 优化器可以自由地动态优化它,而不管您的硬件可能提供的支持如何。

由于这是动态的,它可能会也可能不会优化您在该线程中未更改的字段的读取。

Can anyone see a compiler optimization that Java does (which is not done by C compiler), which is causing this behavior?

优化很可能是将读取缓存在寄存器中或完全消除代码。此优化通常需要大约 10-30 毫秒,因此您要测试此优化是否在程序完成之前发生。

Is there something additional that the Compiler has to do, to get Cache coherence even if the hardware already supports it? (like enable/disable)

您必须正确使用模型,忘记编译器将优化您的代码的想法,理想情况下使用并发库在线程之间传递工作。

public static void main(String... args) {
final AtomicBoolean flag = new AtomicBoolean(true);
/*
* Thread1: Sleeps for 30ms and then sets i to 1
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(30);
System.out.println("Thread1: flag=" + flag);
flag.set(false);
} catch (Exception e) {
throw new RuntimeException("Thread1 Error");
}
}
}).start();

/*
* Thread2: Loops until flag is false and then exits.
*/
new Thread(new Runnable() {
@Override
public void run() {
long j = 0;
while (flag.get())
j++;
System.out.println("\nThread2: flag=" + flag + ", j=" + j);
}
}).start();
}

打印

Thread1: flag=true

Thread2: flag=false, j=39661265

Should I be using Volatile for all shared variables by default?

几乎没有。如果你有一个 since 标志,如果你只设置一次,它就会起作用。但是,通常使用锁定更有用。

关于java - 并发:缓存一致性问题还是编译器优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13018486/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com