Android JNI线程的同步 (十三)

本文介绍了在AndroidStudio中使用JNI进行线程同步的方法,涉及pthread_mutex_t互斥锁和pthread_cond_t条件变量的概念和应用。通过示例展示了如何创建JNI函数,以及在C++中实现线程的等待和唤醒,防止死锁,并分析了代码流程。
摘要由CSDN通过智能技术生成

🔥 Android Studio 版本 🔥  

 🔥 了解线程同步的两个变量  🔥

pthread_mutex_t 互斥锁

线程的互斥:  目前存在两个线程 , 线程A和线程B, 只允许只有一个资源对临界资源进程操作 (大概意思就是 : A线程 进入操作临界资源的时候 , 那么 B线程 就要进行等待 . 等到 A线程 操作临界资源完成退出临界区后, 这时候 B线程 才能对临界区进行访问 .) . 每次保障只有线程访问临界资源 .  线程锁就是起到保护的作用 , 我们可以对某一个临界区进行加锁 .  在任意时间只有线程 执行临界区的代码.  这样就实现了多线程之间的互斥 . 

pthread_mutex_t 条件变量

条件变量 : 是用来实现线程之间的 唤醒和释放 , 我们可以控制线程进行等待 , 线程等待之后可以通知线程结束等待 后继续执行  . 

互斥锁使用不当就会造成线程之间的死锁 ,  就会造成线程一直等待 . 

🔥 创建JNI  🔥

package com.cmake.ndk1.jni;

public class JNIWaitNotify {

    static {
        System.loadLibrary("wait-notify-lib");
    }

    public native void  waitNativeThread();

    public native void  notifyNativeThread();
    
}

 🔥 添加动态库配置 🔥 

add_library(
        #动态库名称 wait-notify-lib
        wait-notify-lib

        SHARED

        jni/jni_wait_notify.cpp
)

🔥 生成可关联的库链接 🔥 

为了让Java能够调用 wait-notify-lib 库中的函数,您需要使用 CMake 构建脚本中的 target_link_libraries() 命令来关联wait-notify-lib 库

target_link_libraries( # Specifies the target library.
        ndk1
        person-lib
        dynamic-lib
        basic-type-lib
        string-lib
        reference-type-lib
        access-field-lib
        access-method-lib
        invoke-method-lib
        constructor-class-lib
        reference-lib
        exception-lib
        thread-lib
        wait-notify-lib
        # Links the target library to the log library
        # included in the NDK. )
        )

🔥 Native层通过 waitNativeThread 实现线程阻塞 🔥 

#include <jni.h>
#include <pthread.h>
#include <jvm.h>

pthread_mutex_t mutex;
pthread_cond_t cond;
//创建两个线程的句柄
pthread_t waitHandle;
pthread_t notifyHandle;

//设置一个线程等待的标志
int flag=0;

//创建线程运行的函数
void *waitThread(void *){
    LOGI("wait thread lock");
    //临界区进行加锁
    pthread_mutex_lock(&mutex);

    //如果flag=0,就让线程一直等待
    while (flag ==0 ) {
        LOGI("waiting");
        //做一个线程等待操作
        pthread_cond_wait(&cond, &mutex);
    }
    LOGI("wait thread unlock");
    //临界区锁进行释放
    pthread_mutex_unlock(&mutex);
    //加上线程退出的函数,显示退出
    pthread_exit(0);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_cmake_ndk1_jni_JNIWaitNotify_waitNativeThread(JNIEnv *env, jobject thiz) {
    //初始化
    pthread_mutex_init(&mutex, nullptr);
    pthread_cond_init(&cond, nullptr);

    pthread_create(&waitHandle, nullptr,waitThread, nullptr);
}
运行结果
package com.cmake.ndk1;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.cmake.ndk1.jni.JNIThread;
import com.cmake.ndk1.jni.JNIWaitNotify;

public class MainActivity13 extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final JNIWaitNotify jniWaitNotify = new JNIWaitNotify();
        final TextView textView = findViewById(R.id.sample_text);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                jniWaitNotify.waitNativeThread();
                //jniWaitNotify.notifyNativeThread();
            }
        });
    }
}
I/LOG_JNI: wait thread lock
I/LOG_JNI: waiting

🔥 Native层通过 notifyNativeThread 实现线程唤醒 🔥  

#include <jni.h>
#include <pthread.h>
#include <jvm.h>

pthread_mutex_t mutex;
pthread_cond_t cond;
//创建两个线程的句柄
pthread_t waitHandle;
pthread_t notifyHandle;

//设置一个线程等待的标志
int flag=0;

//创建线程运行的函数
void *waitThread(void *){
    LOGI("wait thread lock");
    //临界区进行加锁
    pthread_mutex_lock(&mutex);

    //如果flag=0,就让线程一直等待
    while (flag ==0 ) {
        LOGI("waiting");
        //做一个线程等待操作
        pthread_cond_wait(&cond, &mutex);
    }
    LOGI("wait thread unlock");
    //临界区锁进行释放
    pthread_mutex_unlock(&mutex);
    //加上线程退出的函数,显示退出
    pthread_exit(0);
}

//唤起线程中改变flag的值
void *notifyThread(void *){
    LOGE("notify thread lock");
    //临界区进行加锁
    pthread_mutex_lock(&mutex);
    //改变flag的值等于1,唤起线程 释放锁
    flag=1;
    //临界区锁进行释放
    pthread_mutex_unlock(&mutex);
    //唤醒上一个阻塞的线程
    pthread_cond_signal(&cond);
    LOGE("signal......");
    LOGE("notify thread unlock");
    //加上线程退出的函数,显示退出
    pthread_exit(0);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_cmake_ndk1_jni_JNIWaitNotify_waitNativeThread(JNIEnv *env, jobject thiz) {
    //初始化
    pthread_mutex_init(&mutex, nullptr);
    pthread_cond_init(&cond, nullptr);

    pthread_create(&waitHandle, nullptr,waitThread, nullptr);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_cmake_ndk1_jni_JNIWaitNotify_notifyNativeThread(JNIEnv *env, jobject thiz) {
    pthread_create(&notifyHandle, nullptr,notifyThread, nullptr);
}

运行结果 :

package com.cmake.ndk1;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import com.cmake.ndk1.jni.JNIThread;
import com.cmake.ndk1.jni.JNIWaitNotify;

public class MainActivity13 extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final JNIWaitNotify jniWaitNotify = new JNIWaitNotify();
        final TextView textView = findViewById(R.id.sample_text);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                jniWaitNotify.waitNativeThread();
                jniWaitNotify.notifyNativeThread();
            }
        });
    }
}
I/LOG_JNI: wait thread lock
I/LOG_JNI: wait thread unlock
E/LOG_JNI: notify thread lock
E/LOG_JNI: signal......
E/LOG_JNI: notify thread unlock

 🔥 线程阻塞唤醒代码流程梳理 🔥

//创建线程运行的函数
void *waitThread(void *){
    LOGI("wait thread lock");
    //临界区进行加锁
    pthread_mutex_lock(&mutex);

    //如果flag=0,就让线程一直等待
    while (flag ==0 ) {
        LOGI("waiting");
        //做一个线程等待操作
        pthread_cond_wait(&cond, &mutex);
    }
    LOGI("wait thread unlock");
    //临界区锁进行释放
    pthread_mutex_unlock(&mutex);
    //加上线程退出的函数,显示退出
    pthread_exit(0);
}

 做一个线程等待操作 (pthread_cond_wait)  前面加一个临界锁 (pthread_mutex_lock) , 当其他函数想要持有这个临界锁是持有不到的 , 因为我们这里并没有执行释放锁 (pthread_mutex_unlock) . 

当我们调用了线程等待操作 ( pthread_cond_wait ) , 就会将线程放到阻塞的线程队列中去 (即:  待唤醒的线程队列中去 )  并释放锁 , 

//唤起线程中改变flag的值
void *notifyThread(void *){
    LOGE("notify thread lock");
    //临界区进行加锁
    pthread_mutex_lock(&mutex);
    //改变flag的值等于1,唤起线程 释放锁
    flag=1;
    //临界区锁进行释放
    pthread_mutex_unlock(&mutex);
    //唤醒上一个阻塞的线程
    pthread_cond_signal(&cond);
    LOGE("signal......");
    LOGE("notify thread unlock");
    //加上线程退出的函数,显示退出
    pthread_exit(0);
}

唤起线程里面的 临界区进行加锁 (pthread_mutext_lock) 其实用处不大 , 是因为这个锁已经被 waitThread 函数里面的 线程等待操作 (pthread_cond_wait) 持有锁了 ,  只有 pthread_cond_wait 释放了锁, 那么 pthread_mutext_lock 才会拿到互斥锁 继续往下执行 , 指导释放锁 . 

为什么加上锁 ( pthread_mutex_lock )和释放锁  (pthread_mutext_unlock)  , 如果不加即便执行了唤醒线程提示(pthread_cond_signal) 执行了 , 那么线程等待操作 ( pthread_cond_wait ) 也不会执行 . 所以调用了 唤醒线程提示(pthread_cond_signal) 就会出现唤醒丢失的情况 . 

下载案例

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

️ 邪神

你自己看着办,你喜欢打赏我就赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值