这个pthread.h文件可以在NDK环境里创建子线程,并对线程能够做出互斥所、等待、销毁等控制。

写这个博客的原因是我要写如何使用FFmpeg播放视频,因为同时需要播放音频和视频所以需要开启线程,并设置生产者和消费者的关系。

好了直接上整体

1.开启和销毁线程

pthread_create函数能够创建线程,第一个参数是线程的引用,第二个是线程的属性,一般为NULL,第三个为线程运行的函数,第四个是给线程运行函数的参数

pthread_create又是开启线程,只要运行了这个函数线程就会运行起来,也就是运行第三个参数所代表的函数

    pthread_t pthreads;
pthread_create(&pthreads, NULL, threadFunc, (void *) "zzw");

等待线程完成和返回参数,这个如果开启线程只有一个可以不写,但是如果有多个线程这个就必须要写,不写的话只会运行第一个线程

    int retvalue;
pthread_join(pthreads,(void**)&retvalue);
if(retvalue!=0){
__android_log_print(ANDROID_LOG_ERROR,"hello","thread error occurred");
}

我们再来看看线程运行函数,这个他可以获取参数,并且能能够提前结束线程

void * threadFunc(void *arg){

    char* str=(char*)arg;

    for(int i=0;i<3;i++){
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d arg = %s",i,str);
//线程自杀,需要返回参数
//pthread_exit((void*)2);
//线程他杀
//pthread_cancel()
}
return (void *) 0; }

完整例子代码

#include <jni.h>
#include <string>
#include <android/log.h>
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"LC XXX",FORMAT,##__VA_ARGS__); extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_zth_ndkthread_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
} void * threadFunc(void *arg){ char* str=(char*)arg; for(int i=0;i<3;i++){
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d arg = %s",i,str);
//线程自杀,需要返回参数
//pthread_exit((void*)2);
//线程他杀
//pthread_cancel()
}
return (void *) 0; } extern "C"
JNIEXPORT void JNICALL
Java_com_example_zth_ndkthread_MainActivity_startNativeThread(JNIEnv* env, jobject thiz,jint count) { pthread_t pthreads;
pthread_create(&pthreads, NULL, threadFunc, (void *) "zzw"); int retvalue;
pthread_join(pthreads,(void**)&retvalue);
if(retvalue!=0){
__android_log_print(ANDROID_LOG_ERROR,"hello","thread error occurred");
} }

2.互斥锁

互斥锁指的是它能够锁住一段代码,使得这段代码在解锁之前不能再被执行一次,

初始化

    pthread_mutex_t pthread_mutex;
if(pthread_mutex_init(&pthread_mutex,NULL)!=0)
return;

开启线程时把互斥锁传给线程运行函数

    for(int i=0;i<count;i++){
pthread_create(&pthreads[i],NULL,threadFunc,&pthread_mutex);
}

我们再来看看线程运行函数
取出互斥锁并上锁

    pthread_mutex_t* pthread_mutex=(pthread_mutex_t*)arg;
pthread_mutex_lock(pthread_mutex);

然后一段代码

    for(int i=0;i<3;i++){
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",i);
}
__android_log_print(ANDROID_LOG_VERBOSE,"hello","————————————");

解锁

pthread_mutex_unlock(pthread_mutex);

最后销毁互斥锁

    pthread_mutex_destroy(&pthread_mutex);

运行效果如下

03-02 14:25:58.346 10022-10077/com.example.zth.ndkthread V/hello: i = 0
03-02 14:25:58.346 10022-10077/com.example.zth.ndkthread V/hello: i = 1
03-02 14:25:58.346 10022-10077/com.example.zth.ndkthread V/hello: i = 2
03-02 14:25:58.346 10022-10077/com.example.zth.ndkthread V/hello: ------------------------
03-02 14:25:58.346 10022-10078/com.example.zth.ndkthread V/hello: i = 0
03-02 14:25:58.346 10022-10078/com.example.zth.ndkthread V/hello: i = 1
03-02 14:25:58.346 10022-10078/com.example.zth.ndkthread V/hello: i = 2
03-02 14:25:58.346 10022-10078/com.example.zth.ndkthread V/hello: ------------------------
03-02 14:25:58.347 10022-10079/com.example.zth.ndkthread V/hello: i = 0
03-02 14:25:58.347 10022-10079/com.example.zth.ndkthread V/hello: i = 1
03-02 14:25:58.347 10022-10079/com.example.zth.ndkthread V/hello: i = 2
03-02 14:25:58.347 10022-10079/com.example.zth.ndkthread V/hello: ————————————

如果我们没有加锁呢

    pthread_mutex_t* pthread_mutex=(pthread_mutex_t*)arg;
// pthread_mutex_lock(pthread_mutex);
for(int i=0;i<3;i++){
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",i);
}
__android_log_print(ANDROID_LOG_VERBOSE,"hello","------------------------");
// pthread_mutex_unlock(pthread_mutex);

结果如下

03-02 14:36:50.035 13815-13993/com.example.zth.ndkthread V/hello: i = 0
03-02 14:36:50.035 13815-13993/com.example.zth.ndkthread V/hello: i = 1
03-02 14:36:50.035 13815-13993/com.example.zth.ndkthread V/hello: i = 2
03-02 14:36:50.035 13815-13993/com.example.zth.ndkthread V/hello: ------------------------
03-02 14:36:50.035 13815-13994/com.example.zth.ndkthread V/hello: i = 0
03-02 14:36:50.035 13815-13994/com.example.zth.ndkthread V/hello: i = 1
03-02 14:36:50.035 13815-13994/com.example.zth.ndkthread V/hello: i = 2
03-02 14:36:50.035 13815-13995/com.example.zth.ndkthread V/hello: i = 0
03-02 14:36:50.035 13815-13994/com.example.zth.ndkthread V/hello: ------------------------
03-02 14:36:50.035 13815-13995/com.example.zth.ndkthread V/hello: i = 1
03-02 14:36:50.035 13815-13995/com.example.zth.ndkthread V/hello: i = 2
03-02 14:36:50.035 13815-13995/com.example.zth.ndkthread V/hello: ------------------------

所以互斥锁是先让一个线程做完,然后另外一个线程做。

例子代码:

#include <jni.h>
#include <string>
#include <android/log.h>
#include "pthread.h"
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"LC XXX",FORMAT,##__VA_ARGS__); extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_zth_ndkthread_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
} void * threadFunc(void *arg){ pthread_mutex_t* pthread_mutex=(pthread_mutex_t*)arg;
pthread_mutex_lock(pthread_mutex);
for(int i=0;i<3;i++){
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",i);
}
__android_log_print(ANDROID_LOG_VERBOSE,"hello","------------------------");
pthread_mutex_unlock(pthread_mutex);
return (void *) 0;
} extern "C"
JNIEXPORT void JNICALL
Java_com_example_zth_ndkthread_MainActivity_startNativeThread(JNIEnv* env, jobject thiz,jint count) { pthread_mutex_t pthread_mutex;
if(pthread_mutex_init(&pthread_mutex,NULL)!=0)
return; pthread_t pthreads[count];
for(int i=0;i<count;i++){
pthread_create(&pthreads[i],NULL,threadFunc,&pthread_mutex);
} for(int i=0;i<count;i++){
int retvalue=0;
pthread_join(pthreads[i],(void**)&retvalue);
if(retvalue!=0){
__android_log_print(ANDROID_LOG_ERROR,"hello","thread error occurred");
}
} pthread_mutex_destroy(&pthread_mutex); }

3.条件变量

视频解码的绘制使用的就是生产者—消费者的模式。比如说我们生产者生成的产品,放到一个队列里面,当生产者生产出产品的时候就会发送信号通知消费者去消费

这个条件变量能够唤醒线程运行

初始化

pthread_cond_init(&c,NULL);

开启生成者线程和消费者线程

    pthread_create(&thread_producer, NULL, produce, (void *) "producer");
pthread_create(&thread_comsumer, NULL, comsume, (void *) "comsumer");

循环生产产品,然后提醒消费者

    for(;;){
pthread_mutex_lock(&m);
productNum++;
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",productNum);
pthread_cond_signal(&c);
pthread_mutex_unlock(&m); }

消费者线程如果发现没有产品就等待条件变量提醒,,如果有产品就消费掉

        pthread_mutex_lock(&m);
while(productNum == 0){
pthread_cond_wait(&c,&m); }
productNum--;
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",productNum);
pthread_mutex_unlock(&m);

注意生成者与消费者线程运行的全过程都在互斥锁下,都是按顺序一一执行的,这样对于全局变量productNum的计算就不会错误,并且通过一个线程执行pthread_cond_signal来触发另一个线程执行

例子代码

#include <jni.h>
#include <string>
#include <android/log.h>
#include "pthread.h"
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"LC XXX",FORMAT,##__VA_ARGS__); extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_zth_ndkthread_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
} int productNum = 0;
pthread_mutex_t m;
pthread_cond_t c; void *produce(void* arg){
char* no = (char*)arg;
for(;;){
pthread_mutex_lock(&m);
productNum++;
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",productNum);
pthread_cond_signal(&c);
pthread_mutex_unlock(&m); }
} void *comsume(void* arg){
char* no = (char*)arg;
for(;;){
pthread_mutex_lock(&m);
while(productNum == 0){
pthread_cond_wait(&c,&m); }
productNum--;
__android_log_print(ANDROID_LOG_VERBOSE,"hello","i = %d",productNum);
pthread_mutex_unlock(&m); }
} extern "C"
JNIEXPORT void JNICALL
Java_com_example_zth_ndkthread_MainActivity_startNativeThread(JNIEnv* env, jobject thiz,jint count) { pthread_mutex_init(&m,NULL);
pthread_cond_init(&c,NULL); pthread_t thread_producer;
pthread_t thread_comsumer; pthread_create(&thread_producer, NULL, produce, (void *) "producer");
pthread_create(&thread_comsumer, NULL, comsume, (void *) "comsumer"); pthread_join(thread_producer,NULL);
pthread_join(thread_comsumer,NULL); pthread_mutex_destroy(&m);
pthread_cond_destroy(&c); }

参考文章

https://www.jianshu.com/p/453d12c16885

http://blog.csdn.net/lxmhuendan/article/details/11967593

Android NDK pthreads详细使用的更多相关文章

  1. Android NDK 交叉编译C++代码生成.so共享库详细步骤

    Android NDK 交叉编译C++代码生成.so共享库详细步骤 Android NDK 调用c++ stl 模板库(修改android.mk文件) 1  在需要调用模板库的文件前包含头文件:   ...

  2. Android NDK开发入门实例

    AndroidNDK是能使Android应用开发者把从c/c++编译而来的本地代码嵌入到应用包中的一系列工具的组合. 注意: AndroidNDK只能用于Android1.5及以上版本中. I. An ...

  3. [原]如何用Android NDK编译FFmpeg

    我们知道在Ubuntu下直接编译FFmpeg是很简单的,主要是先执行./configure,接着执行make命令来编译,完了紧接着执行make install执行安装.那么如何使用Android的ND ...

  4. !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结

    http://hujiaweibujidao.github.io/blog/2013/11/18/android-ndk-and-opencv-development-3/ Android Ndk a ...

  5. Android NDK 和 OpenCV 整合开发总结(3)

    Android NDK 和 OpenCV 整合开发总结(3) http://hujiaweibujidao.github.io/blog/2013/11/18/android-ndk-and-open ...

  6. Android NDK开发之Android.mk文件

    Android NDK开发指南---Android.mk文件 博客分类: Android NDK开发指南   Android.mk文件语法详述 介绍: ------------ 这篇文档是用来描述你的 ...

  7. Android NDK开发指南---Application.mk文件和android.mk文件

    https://android.googlesource.com/platform/development/+/donut-release/ndk/docs/OVERVIEW.TXT https:// ...

  8. android ndk通过遍历和删除文件

           在做移动开发过程,难免有些本地文件管理操作.例如,很常见app随着微博.微信要清除缓存功能,此功能是走app文件夹.然后删除所有缓存文件.使用java的File类能够实现本地文件遍历及删 ...

  9. Android NDK的C++11标准支持

    C++11于Android NDK它已被支持,本文介绍了如何NDK添加C++11支持标准. 在开源项目Cocos2d-x于,他已经加入C++11支持标准. 1.改动Application.mk文件,加 ...

随机推荐

  1. Gitlab安装、汉化及使用

    环境:centos 关闭防火墙和selinux [root@Gitlab ~]# setenforce [root@Gitlab ~]# service iptables stop && ...

  2. springboot+thymeleaf+pageHelper带条件分页查询

    html层 <div> <a class="num"><b th:text="'共 '+ ${result.resultMap['pages ...

  3. python 基于numpy的线性代数运算

    import numpy as np A = [[1,2],[2,1]] np.linalg.inv(A)  #计算矩阵A的逆矩阵. #显示结果 [[-0.33333333 0.66666667] [ ...

  4. linux awk用法

    awk是一个强大的文本分析工具,在对数据进行分析并生成报告时显得尤为强大. 使用方法:awk [options]  'BEGIN{ commands } pattern{ commands } END ...

  5. Bytom储蓄分红合约解析

    储蓄分红合约简介 储蓄分红合约指的是项目方发起了一个锁仓计划(即储蓄合约和取现合约),用户可以在准备期自由选择锁仓金额参与该计划,等到锁仓到期之后还可以自动获取锁仓的利润.用户可以在准备期内(dueB ...

  6. LINUX之根目录介绍、普通目录创建、删除、复制、移动、权限管理命令记录

    (一)Linux 系统目录结构 登录系统后,在当前命令窗口下输入命令:ls / /bin:bin是Binary的缩写, 这个目录存放着最经常使用的命令. /boot:这里存放的是启动Linux时使用的 ...

  7. Pandas 基础(14) - DatetimeIndex and Resample

    这一小节要介绍两个内容, 一个是 DatetimeIndex 日期索引, 另一个是 Resample, 这是一个函数, 可以通过参数的设置, 来调整数据的查询条件, 从而得到不同的结果. 首先看下关于 ...

  8. 根据不同浏览器判断OCX插件是否安装

    最近项目进入到了验收阶段,需要兼容不同的浏览器,海康的Demo写了一个判断插件是否成功安装的函数,但是经过测试,只在IE浏览器下有效果,在其他的浏览器下面会出现Bug,现在需要写一个通用的方法,在不同 ...

  9. 开启BBR

    BBR 目的是要尽量跑满带宽, 并且尽量不要有排队的情况, 效果并不比速锐差Linux kernel 4.9+ 已支持 tcp_bbr 下面简单讲述基于KVM架构VPS如何开启附:OpenVZ 架构V ...

  10. vue admin mock数据

    搭建脚手架axios访问不到接口:mock数据的问题mock下的index.js设置了默认指向