Android NDK pthreads詳細使用

來源:互聯網
上載者:User

標籤:NDK   pthread   線程   

這個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詳細使用

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.