Linux生产者消费者模型与C/C++子线程调用Java
2019-06-10 本文已影响0人
小小混世魔王
生产者消费者模型
基于生产者和消费者的模型在编程中运用是较多。生产者是一个或者多个线程产生数据,消费者是另一个或者多个线程处理数据,内存缓冲区可以使用集合数组队列方式,主要是用来协调生产者和消费者之间的数据产生和消费平衡。关键是如何处理多线程之间的协作。
在这个模型中,内存缓冲区为空的时候消费者处于等待状态待生产者唤醒,当内存缓冲区满的时候,生产者处于等待状态待消费者唤醒。当内存缓冲区有产品没有达到最大容量时生产者和消费者是处于一个动态平衡状态。设计到多线程,保证数据的正确新所以就需要锁来保证。
#include <jni.h>
#include <string>
#include <pthread.h>
#include <android/log.h>
#include <queue>
#include <unistd.h>
pthread_t product_thread, consumer_thread;
pthread_mutex_t mutex;
pthread_cond_t condition;
std::queue<int> product_queue;
bool is_exit = false;
/**
*生产者
*/
void *product(void *arg) {
__android_log_print(ANDROID_LOG_ERROR, "thread_demo", "%s", (char *) arg);
while (!is_exit) {
//加锁
pthread_mutex_lock(&mutex);
product_queue.push(1);
__android_log_print(ANDROID_LOG_ERROR, "thread_demo", "生产者生产产品%d", product_queue.size());
//通知消费者消费
pthread_cond_signal(&condition);
//释放锁
pthread_mutex_unlock(&mutex);
sleep(2);
}
return NULL;
}
/**
*消费者
*/
void *consumer(void *arg) {
__android_log_print(ANDROID_LOG_ERROR, "thread_demo", "%s", (char *) arg);
while (!is_exit) {
pthread_mutex_lock(&mutex);
if (!product_queue.empty()) {
product_queue.pop();
__android_log_print(ANDROID_LOG_ERROR, "thread_demo", "消费者消费产品%d", product_queue.size());
} else{
//等待生产者 阻塞 会把锁释放
__android_log_print(ANDROID_LOG_ERROR, "thread_demo", "消费者%s","等待生产者生产产品");
pthread_cond_wait(&condition, &mutex);
}
pthread_mutex_unlock(&mutex);
usleep(1000 * 500);
}
return NULL;
}
/**
* 生产者 消费者
*/
extern "C"
JNIEXPORT void JNICALL
Java_com_youyangbo_thread_MainActivity_productConsumer(JNIEnv *env, jobject instance) {
int i = 0;
for (; i < 10; ++i) {
product_queue.push(i);
}
//初始化锁
pthread_mutex_init(&mutex, NULL);
//初始化条件
pthread_cond_init(&condition, NULL);
//创建线程
pthread_create(&product_thread, NULL, product, (void *) "product");
pthread_create(&consumer_thread, NULL, consumer, (void *) "consumer");
//阻塞等待线程完毕
pthread_join(product_thread, NULL);
pthread_join(consumer_thread, NULL);
}
C/C++子线程调用java方法
C/C++与java之间的互相调用是要通过JNI来实现的,JNIEnv是与线程之间有关系的,不同的线程JNIEnv是不同的,当我们在c/c++层创建一个子线程要用到JNIEnv,这个子线程的JNIEnv如何得到呢?获取到JavaVM 然后通过JavaVM 调用AttachCurrentThread(JNIEnv** p_env, void* thr_args)来的到JNIEnv。JavaVM 怎么得到呢?在java调用native方法是会先执行JNI_OnLoad(JavaVM* vm, void* reserved),还需要注意一个细节就是获取MethodID不能够在子线程获取。需要放在主线程,创建 instance参数所引用对象的新全局引用 obj = env->NewGlobalRef(instance);
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("native-lib");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
callLog();
}
public native void callLog();
public void loge() {
Log.e( "loge: ", "被c++子线程调用了");
}
}
#include <jni.h>
#include <string>
#include <pthread.h>
#include <android/log.h>
JavaVM *java_vm;
jmethodID jmid;
jobject obj;
void *thread_callBack(void *arg) {
JNIEnv *env;
java_vm->AttachCurrentThread(&env, NULL);
if (!obj){
pthread_exit(0);
}
env->CallVoidMethod(obj, jmid);
java_vm->DetachCurrentThread();
return NULL;
}
extern "C"
JNIEXPORT void JNICALL
Java_com_youyangbo_thread_MainActivity_callLog(JNIEnv *env, jobject instance) {
obj = env->NewGlobalRef(instance);
jclass clz = env->GetObjectClass(obj);
jmid = env->GetMethodID(clz, "loge", "()V");
pthread_t pthread;
pthread_create(&pthread, NULL, thread_callBack, NULL);
pthread_join(pthread, NULL);
env->DeleteGlobalRef(obj);
}
extern "C"
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
java_vm = vm;
if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
return JNI_VERSION_1_6;
}