while循环中的一个变量未更改,ndk/android

while循环中的一个变量未更改,ndk/android,android,c++,android-ndk,Android,C++,Android Ndk,我是ndk的新手。你能解释一下下面的情况吗。 这是我的简单代码示例: 回路c test.cpp 在java端,我有两个带有单击侦听器的按钮: mStart = (Button) findViewById(R.id.button1); mStop = (Button) findViewById(R.id.button2); mStart.setOnClickListener(new OnClickListener() { @Override public void onClick

我是ndk的新手。你能解释一下下面的情况吗。 这是我的简单代码示例:

回路c

test.cpp

在java端,我有两个带有单击侦听器的按钮:

mStart = (Button) findViewById(R.id.button1);
mStop = (Button) findViewById(R.id.button2);

mStart.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        exec.execute(new Runnable() {
            @Override
            public void run() {
                Start();
            }
        });
    }
});

mStop.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        exec.execute(new Runnable() {
            @Override
            public void run() {
                Stop();
            }
        });
    }
});
和服务执行人:

private Executor exec = Executors.newCachedThreadPool();
我在MSStart按下后执行启动循环。 之后,我点击mStop并等待循环停止。 但什么也没发生。 在adb控制台中,我只看到

D/TEST    (17456): in the loop
D/TEST    (17456): in the loop
D/TEST    (17456): in the loop
..............................
D/TEST    (17456): in the loop
D/TEST    (17456): in the loop
信息


有人能帮我吗?如何停止循环?

您的两个功能未正确同步。它们由不同的线程调用,一个线程通过单击mStart启动,另一个线程通过单击mStop启动。这本身不是问题。两个线程并行调用本机函数也不是问题。但当本机函数都试图同时访问标志时,这确实会成为一个问题

你需要同步。否则,最基本的事情可能会出错。例如,根本不能保证线程2会看到线程1中变量的更改。即使是像flag++这样的简单表达式也不再是原子表达式,可能会导致各种奇怪的效果。如果没有同步,你的应用程序就会随机化,导致崩溃

同步可以在C++和java中完成,但是对于JNI用例,通常最好将所有同步保留到java端。这只是JNI的通用软件工程指南:

尽可能使用Java,必要时使用本机

在您的情况下,可能的解决方案是将循环和标志移动到java,并将JNI函数还原为C++中真正必须完成的功能。停止函数将完全用Java编写,取消标志将变成:

Start函数也将成为一个Java方法,并封装一个更简单的JNI函数:

private native void print();

private void start() {
    while (!cancel.get()) {
        print();
    }
} 
void test_loop() {
    __android_log_print(ANDROID_LOG_DEBUG, "TEST", "in the loop");
}
以下是简化的JNI函数:

private native void print();

private void start() {
    while (!cancel.get()) {
        print();
    }
} 
void test_loop() {
    __android_log_print(ANDROID_LOG_DEBUG, "TEST", "in the loop");
}
这里有一个重要的最后提示:您可能应该使用Android SDK的类,该类专门为可取消的后台操作而设计

编辑:原始答案有一个bug。Java代码现在使用AtomicBoolean,这应该可以解决问题。

编译器将在更高的优化级别将whileflag转换为while1,因为它会认为没有人在更新标志。您可以通过将标志定义为volatile来避免这种情况,这意味着有人可以从外部更新此变量


静态int标志=1;->静态易失性int标志=1

听说过锁、易失性锁、同步锁、互斥锁、信号量锁吗?那你应该知道出了什么问题。非常感谢你的帮助。这不就是僵局吗?“开始”正在执行时,您不能调用“停止”。恐怕您是对的。我最初有额外的私有同步方法,然后在发布之前对其进行了优化。我真傻。我看看今天晚些时候能不能找到答案!
private native void print();

private void start() {
    while (!cancel.get()) {
        print();
    }
} 
void test_loop() {
    __android_log_print(ANDROID_LOG_DEBUG, "TEST", "in the loop");
}