Android-Jni线程(二)— 线程锁之生产者消费者

 

 

我的视频课程(基础):《(NDK)FFmpeg打造Android万能音频播放器》

我的视频课程(进阶):《(NDK)FFmpeg打造Android视频播放器》

我的视频课程(编码直播推流):《Android视频编码和直播推流》

我的视频课程(C++ OpenGL):《Android C++ OpenGL教程》

 

 

目录:

        Android-Jni线程(一)— 创建线程

        Android-Jni线程(二)— 线程锁之生产者消费者

        Android-Jni线程(三)— JNI全局回调java方法

 

 

 

        上一篇博客《Android-Jni线程(一)— 创建线程》我们在Jni层创建了一个最简单的线程但啥事也没有做,总感觉没什么实际的作用,现在我们就来实现经典的“生产者和消费者”线程锁模型。先看看演示效果:

 

Android-Jni线程(二)— 线程锁之生产者消费者_第1张图片

 

首先还是老规矩先讲讲大体步骤:

1、创建生产者和消费者2个线程:pthread_t   pthread_produc,pthread_customer。

2、创建线程锁和条件对象:pthread_mutex_t mutex和pthread_cond_t cond。

3、创建产品队列queue(C++中“queue”头文件)。

5、生产者定时生产产品往队列queue添加(push)产品,并通知(pthread_cond_signal)消费者可以消费了;消费者快速从queue取出(pop)产品消费,当queue中没有产品(size == 0)时,就阻塞等待(pthread_cond_wait)生产者生产产品后的通知并马上消费。

6、生产者添加产品(queue.push)和消费者消费产品(queue.pop)时都在线程锁中(pthread_mutex_lock)执行,当添加/消费产品后就解锁线程(pthread_mutex_unlock),这样就能保证同一时刻只有生产者或消费者才能对产品进行操作。

接下来Jni中用C++代码实现:

 

#include 

#include "AndroidLog.h"
#include "pthread.h"
#include "unistd.h"
#include "queue"

//1、一般线程
pthread_t pthread;//线程对象
void *threadDoThings(void *data)
{
    LOGD("jni thread do things");
    pthread_exit(&pthread);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_ywl5320_jnithread_JniThread_normalThread(JNIEnv *env, jobject instance) {
    // TODO
    LOGD("normal thread");
    //创建线程
    pthread_create(&pthread, NULL, threadDoThings, NULL);

}


//2、线程锁

std::queue queue; //产品队列,里面是int的队列
pthread_t pthread_produc; //生产者线程
pthread_t pthread_customer; //消费者线程
pthread_mutex_t mutex; //线程锁
pthread_cond_t cond; //条件对象


void *ptoducThread(void *data)
{
    while(queue.size() < 50)
    {
        LOGD("生产者生产一个产品");
        pthread_mutex_lock(&mutex); //操作队列前先加锁
        queue.push(1);
        if(queue.size() > 0)
        {
            LOGD("生产者通知消费者有产品产生,产品数量为:%d", queue.size());
            pthread_cond_signal(&cond); //有了产品通知消费者
        }
        pthread_mutex_unlock(&mutex); //解锁线程
        sleep(4); //休息4秒,单位是秒
    }
    pthread_exit(&pthread_produc);
}

void *customerThread(void *data)
{
    char *prod = (char *) data;
    LOGD("%", prod);
    while(1) //这里用死循环,时间情况应该给一个变量来控制跳出循环
    {
        pthread_mutex_lock(&mutex); //操作队列前先加锁
        if(queue.size() > 0)
        {
            queue.pop();
            LOGE("消费者消费一个产品,产品数量为:%d", queue.size());
        } else{
            LOGE("产品消费完了,等待生产者生产......");
            pthread_cond_wait(&cond, &mutex); //阻塞线程等待生产者的通知
        }
        pthread_mutex_unlock(&mutex);//解锁线程
        usleep(500 * 1000); //休息0.5秒,usleep单位是微妙
    }
    pthread_exit(&pthread_customer);
}

void initMutex()
{
    pthread_mutex_init(&mutex, NULL); //初始化锁对象 对应pthread_mutex_destroy销毁锁对象
    pthread_cond_init(&cond, NULL); //初始化条件变量 对应pthread_cond_destroy销毁条件变量
    pthread_create(&pthread_produc, NULL, ptoducThread, (void *) "product"); //创建生产者线程,并传递参数
    pthread_create(&pthread_customer, NULL, customerThread, NULL); //创建消费者线程
}

extern "C"
JNIEXPORT void JNICALL
Java_com_ywl5320_jnithread_JniThread_mutexThread(JNIEnv *env, jobject instance) {
    // TODO
    //初始化时,先往队列中添加10个产品
    for(int i = 0; i < 10; i++)
    {
        queue.push(i);
    }
    initMutex();
}


根据注释和上文的步骤思路就很好理解“生产者和消费者”模型了,在ffmpeg中音视频解码时就用到了这个模型,后面也会介绍用ffmpeg解码音视频的。现在是打基础的时候 哈哈。下一篇博客将介绍:在c++中全局调用java方法达到回调效果。

 

 

源码下载:Github:Android-JniThread 欢迎star

 

 

 

 

 

你可能感兴趣的:(jni线程)