[NDK] -POSIX线程学习一

学习pthread(一)


  • MainActivity.java
package com.zhuhongxi.nativcethreaddemo1;

import androidx.appcompat.app.AppCompatActivity;

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

import com.zhuhongxi.nativcethreaddemo1.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-thread");
    }

    private ActivityMainBinding binding;
    private TextView tvLogView;
    private EditText etThreadNum;
    private EditText etIterNum;
    private Button btnStart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        nativeInit();

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        tvLogView = binding.tvInfo;
        etThreadNum = binding.etThreadNum;
        etIterNum = binding.etThreadIterationNum;
        btnStart = binding.btnStart;

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int threadNum = getNumber(etThreadNum, 1);
                int iterationNum = getNumber(etIterNum, 2);
                if (threadNum > 0 && iterationNum > 0) {
                    startThreads(threadNum, iterationNum);
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        nativeFree();
        super.onDestroy();
    }

    /**
     * native回调java方法
     * @param message native 传过来的消息
     */
    private void onNativeMessage(final String message) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tvLogView.append(message);
                tvLogView.append("\n");
            }
        });
    }


    private static int getNumber(EditText editText, int defaultValue) {
        int value;

        try {
            value = Integer.parseInt(editText.getText().toString());
        } catch (NumberFormatException e) {
            value = defaultValue;
        }
        return value;
    }

    private void startThreads(int threads, int iterations) {
        posixThreads(threads, iterations);
    }


    /**
     * 启动native thread
     * @param threads
     * @param iterations
     */
    private native void posixThreads(int threads, int iterations);

    /**
     * 初始化native资源
     */
    private native void nativeInit();

    /**
     * 释放native资源
     */
    private native void nativeFree();

}
  • native-thread.cpp
#include <jni.h>
#include <string>
#include <cstdio>
#include <pthread.h>
#include <unistd.h>

//线程worker参数
struct NativeWorkerArgs {
    jint id;
    jint iteration;
};

//能被缓存的java方法ID
static jmethodID gOnNativeMessage = nullptr;

// Java VM 接口指针
static JavaVM* gVm = nullptr;

// thiz对象的全局引用
static jobject gObj = nullptr;

/**
 * 当共享库开始加载时,虚拟机自动调用这个函数,可以从这里获取JAVA VM的指针
 * @param vm
 * @param reserved
 * @return
 */
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    //获取JAVA VM 全局指针
    gVm = vm;
    return JNI_VERSION_1_6;
}

static void* nativeWorkerThread(void* args)
{
    JNIEnv* env = nullptr;

    if (0 == gVm->AttachCurrentThread(&env, nullptr))
    {
        NativeWorkerArgs* nativeWorkerArgs = (NativeWorkerArgs*)args;
        //Java_com_zhuhongxi_nativcethreaddemo1_MainActivity_nativeWorker(env, gObj, nativeWorkerArgs->id, nativeWorkerArgs->iteration);
        for (int i = 0; i < nativeWorkerArgs->iteration; ++i) {
            char message[26];
            sprintf(message, "Worker %d: Iteration %d", nativeWorkerArgs->id, i);
            jstring messageString = env->NewStringUTF(message);
            env->CallVoidMethod(gObj, gOnNativeMessage, messageString);
            if (nullptr != env->ExceptionOccurred())
                break;
            sleep(1);
        }
        delete nativeWorkerArgs;
        gVm->DetachCurrentThread();
    }
    return (void*) 1;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zhuhongxi_nativcethreaddemo1_MainActivity_nativeInit(JNIEnv *env, jobject thiz) {

    if (nullptr == gOnNativeMessage)
    {
        //从对象中获取类
        jclass clazz = env->GetObjectClass(thiz);
        //获取java中回调方法的method ID
        gOnNativeMessage = env->GetMethodID(clazz, "onNativeMessage", "(Ljava/lang/String;)V");
        //如果方法没找到就抛出一个异常
        if (nullptr == gOnNativeMessage)
        {
            jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
            env->ThrowNew(exceptionClazz, "Unable to find method");
        }
    }

    if (nullptr == gObj)
    {
        //创建一个全局的引用指向this(这个this是java的上下文,在这里也就是MainActivity)
        gObj = env->NewGlobalRef(thiz);
        if (nullptr == gObj)
        {
            goto exit;
        }
    }

exit:
    return;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_zhuhongxi_nativcethreaddemo1_MainActivity_nativeFree(JNIEnv *env, jobject thiz) {
    if (nullptr != gObj)
    {
        //使用结束后记得释放全局的引用,回收资源
        env->DeleteGlobalRef(gObj);
        gObj = nullptr;
    }
}


extern "C"
JNIEXPORT void JNICALL
Java_com_zhuhongxi_nativcethreaddemo1_MainActivity_posixThreads(JNIEnv *env, jobject thiz,
                                                                jint threads, jint iterations) {
    //为每一个worker创建一个posix线程去执行
    for (jint i = 0; i < threads; i++) {
        //组装每一个worker参数
        NativeWorkerArgs* nativeWorkerArgs = new NativeWorkerArgs();
        nativeWorkerArgs->id = i;
        nativeWorkerArgs->iteration = iterations;
        //创建pthread
        pthread_t thread;
        int result = pthread_create(&thread, nullptr,nativeWorkerThread, (void*)nativeWorkerArgs);
        //如果创建失败就抛出一个java异常
        if (0 != result)
        {
            jclass exceptionClazz = env->FindClass("java/lang/RuntimeException");
            env->ThrowNew(exceptionClazz, "Unable to create native thread");
        }
    }
}

  • CmakeLists.txt
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.10.2)

# Declares and names the project.

project("nativcethreaddemo1")

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
        native-thread

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        native-thread.cpp)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        native-thread

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})
  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/et_thread_num"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Thread Num"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/et_thread_iteration_num"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Iteration Num"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/et_thread_num" />

    <Button
        android:id="@+id/btn_start"
        android:text="Start Threads"
        android:textAllCaps="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/et_thread_iteration_num" />

    <ScrollView
        android:id="@+id/srl_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/btn_start">

        <TextView
            android:id="@+id/tv_info"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </ScrollView>


</androidx.constraintlayout.widget.ConstraintLayout>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

坂田民工

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值