1. 为什么需要 Memory Order
如果不使用任何同步机制(例如 mutex 或 atomic),在多线程中读写同一个变量,那么,程序的结果是难以预料的。主要原因有一下几点:
- 简单的读写不是原子操作
- CPU 可能会调整指令的执行顺序
- 在 CPU cache 的影响下,一个 CPU 执行了某个指令,不会立即被其它 CPU 看见
1.1 非原子操作给多线程编程带来的影响
原子操作说的是,一个操作的状态要么就是未执行,要么就是已完成,不会看见中间状态。
如果不使用任何同步机制(例如 mutex 或 atomic),在多线程中读写同一个变量,那么,程序的结果是难以预料的。主要原因有一下几点:
原子操作说的是,一个操作的状态要么就是未执行,要么就是已完成,不会看见中间状态。
视频课程与答疑服务请咨询微信号 zzh0838
使用命令行的第一步是打开 Terminal 软件:



视频课程与答疑服务请咨询微信号 zzh0838
本文是在Make 命令教程的基础上进行的演绎和补充。
代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。
Make 是最常用的构建工具,诞生于 1977 年,主要用于 C 语言的项目。但是实际上 ,任何只要某个文件有变化,就要重新构建的项目,都可以用 Make 构建。
视频课程与答疑服务请咨询微信号 zzh0838
我们直接看一个示例:
写一个 helloworld c++ 可执行程序:
main.c:
# include <iostream>
int main(int argc, char const *argv[])
{
for(int i = 0; i < 5; ++i)
std::cout << "Hello World" << std::endl;
return 0;
}
视频课程与答疑服务请咨询微信号 zzh0838
学习任何一门编程语言,和小学生学习语文类似,汉字有上万个,但是,小学生在掌握了一到两千字就可以开始阅读了,其中关键就是,小学生有字典。编程技术的学习也类似:找一份薄点的教程,快速上手,官方的文档,相关的书籍教程可以作为我们实践过程中的字典。
这份教程就是我总结的一份薄点的教程
什么是 Shell 脚本?我们把多个 linux 命令写进一个文件,这个文件就叫 shell 脚本。shell 脚本可以重复使用,相比手动输入大大提高了效率。
视频课程与答疑服务请咨询微信号 zzh0838
在 shell 中,可以使用 test 或者 [] 来做判断:
# 使用 $? 查看上一条命令的退出码,0 代表正确(true),非 0 代表错误(false)
#这里的 a b 就是字符串本身,而不是变量
# 注意 == 两边的空格不能少
test a == b ; echo $?
1
test a != b ; echo $?
0
test $a == $b ; echo $? #这里的 a b 是变量
# 注意 == 两边的空格不能少,[ 右侧空格不能少, ] 左侧空格不能少
[ $USER == root ]; echo $?
# 相等输出 Y,不相等输出 N
[ $USER == root ] && echo Y || echo N
[ $USER != root ] && echo Y || echo N
# 用 -z 可以测试一个字符串是否为空
[ -z "$TEST" ] && echo Y || echo N
# -n 测试一个字符串是否非空
# 注意点: $ 引用一个值时,使用 "" 括起来,否则 -n 判断会出错
[ -n "$TEST" ] && echo Y || echo N
JNI 编程是高级/专家 Android 开发的必备技能之一,接下来我们就一步一步掌握 JNI 编程的方方面面。
本文示例代码可以在 https://github.com/yuandaimaahao/AndroidFrameworkTutorial/tree/main/1.%E5%9F%BA%E7%A1%80%E7%AF%87/JNI%20%E7%BC%96%E7%A8%8B%E4%B8%8A%E6%89%8B%E6%8C%87%E5%8D%97/src 这里下载到。
JNI(Java Native Interface,JAVA 原生接口)。JNI 是本地编程接口,它使得在 Java 虚拟机 (VM) 内部运行的 Java 代码能够与用其它编程语言(如 C、C++ 和汇编语言)编写的应用程序和库进行互操作。通俗一点讲就是在 Java 代码里调用 C/C++ 等语言的代码或 C/C++ 代码调用 Java 代码。
JNI 程序中涉及了三种数据类型,分别是:
在 Java 程序中我们使用的是 Java 类型,C/C++ 程序中拿到的是 JNI 类型,我们需要将其转换为 C/C++ 类型,使用 C/C++ 类型再去调用 C/C++ 层函数完成计算或 IO 操作等任务后,将结果再转换为 JNI 类型返回后,在 java 代码中,我们就能收到对应的 Java 类型。
我们可以在 $JAVA_HOME/inlcude/jni.h 文件中查看到 jni 中基本类型的定义:
在 JNI 的 Native 方法中,我们要使用 Java 中的对象怎么办?即在 C/C++ 中怎么找到 Java 中的类,这就要使用到 JNI 开发中的类描述符了
JNI 提供的函数中有个 FindClass() 就是用来查找 Java 类的,其参数必须放入一个类描述符字符串,类描述符一般是类的完整名称(包名+类名)
一个 Java 类对应的描述符,就是类的全名,其中 . 要换成 / :
完整类名: java.lang.String
对应类描述符: java/lang/String
jclass intArrCls = env->FindClass("java/lang/String")
jclass clazz = FindClassOrDie(env, "android/view/Surface");
JNIEnv 即 Java Native Interface Environment,Java 本地编程接口环境。JNIEnv 内部定义了很多函数用于简化我们的 JNI 编程。
JNI 把 Java 中的所有对象或者对象数组当作一个 C 指针传递到本地方法中,这个指针指向 JVM 中的内部数据结构(对象用jobject来表示,而对象数组用jobjectArray或者具体是基本类型数组),而内部的数据结构在内存中的存储方式是不可见的。只能从 JNIEnv 指针指向的函数表中选择合适的 JNI 函数来操作JVM 中的数据结构。