在做NDK开发的时候,很多情况下都是需要使用多线程的,一方面是提高程序运行效率,另一方面就是防止主线程阻塞

C的多线程

在C语言里,可以通过对于POSIX标准的运用,使得C语言执行多线程
提高程序的执行速度,以及对资源的合理利用

POSIX

POSIX原理

POSIX可以让C语言实现多线程
其实现是是通过POSIX函数库的调用实现的
POSIX函数库可以看作是C语言库函数的超集,对C语言尽行了增强

POSIX实现多线程

在C语言中调用POSIX库函数可以实现多线程
在使用时,需要包含pthread.h头文件
其步骤为:

  • 创建线程ID,使用pthread_t创建线程ID
pthread_t tid;
  • 创建线程,使用pthread_create()创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
  • 结束线程
    线程依附于主线程,主线程结束,其子线程也就结束了
    要使主线程等待子线程运行完毕,就需要使用pthread_join()函数
int pthread_join(pthread_t thread, void **retval);

另外,在线程运行的时候可以结束线程,可以通过以下函数结束正在运行的线程

void pthread_exit(void *retval);
int pthread_cancel(pthread_t thread);

e.g.

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>void* thr_fun(void* arg){char* buf = (char*)arg;int i = 0;for(; i < 100; i++){printf("%s thread -%d-\n", buf, i);usleep(1000);}return "thread over\n";
}void main(){pthread_t tid; //创建线程IDpthread_create(&tid, NULL, thr_fun, "pass"); //创建线程并执行thr_fun函数int i = 0;for(; i < 100; i++){printf("main thread -%d-\n", i);usleep(1000);}void* rval;pthread_join(tid, &rval); //等待线程执行完毕printf("get from thread:%s", (char *)rval);
}

上述示例在加入usleep是为了主线程和子线程都能够输出
注意:在编译有posix标准库多线程的时候,应该添加-lpthread参数,否则会报错

/tmp/ccEEnOE4.o: In function `main':
threadtest.c:(.text+0x7f): undefined reference to `pthread_create'
threadtest.c:(.text+0xc3): undefined reference to `pthread_join'
collect2: error: ld returned 1 exit status

互斥锁

为了线程的安全,给线程加上互斥锁,这样就可以确保线程安全
线程锁的作用就是在一个线程进行访问的时候,不允许其他线程进入

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>int count = 0;
pthread_mutex_t mutex; //声明互斥锁void* thr_fun(void* arg){pthread_mutex_lock(&mutex); //加锁char *buf = (char*)arg;for(;count < 5; count++){printf("thread:%s, count:%d\n", buf, count);}count = 0;pthread_mutex_unlock(&mutex); //解锁
}void main(){pthread_t tid1, tid2;pthread_mutex_init(&mutex, NULL); //初始化互斥锁pthread_create(&tid1, NULL, thr_fun, "thread-1");pthread_create(&tid2, NULL, thr_fun, "thread-2");pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_mutex_destroy(&mutex); //销毁互斥锁
}

生产者与消费者

  • 当存在多个线程对同一数据进行操作的时候,那么这个数据如果同时被多个线程操作,就会产生安全问题
  • 比如线程A在访问数据的时候丢失了CPU的控制权,此时线程B去操作了数据,那么线程A在重新得到CPU控制权的时候,其渠道的数据就是线程B操作过的数据,可能其数据并不是预期要取的值
  • 面对这种情况,在设计模式里面就提出了生产者与消费者模型,这也是很常用的一种模型

单个生产者与单个消费者

这种情况下,只需要满足生产者生产出来能及时被消费者消费
其生产者应该上锁,生产,通知消费者,解锁,然后按照这个流程不断循环
消费者应该上锁,消费,通知生产者,解锁,然后按照这个流程不断循环
全局变量

int ready = 0;
int product_idx = 0, consumer_idx = 0;
pthread_mutex_t mutex;
pthread_cond_t has_product;

生产者方法

void* producer(void* arg){char *buf = (char *)arg;while(1){pthread_mutex_lock(&mutex); //上锁ready++; //生产product_idx++;printf("%5d%s----%d\n", product_idx, buf, ready);pthread_cond_signal(&has_product); //通知消费者,会阻塞pthread_mutex_unlock(&mutex); //解锁usleep(100 * 1000);}
}

消费者方法

void* consumer(void* arg){char *buf = (char *)arg;while(1){pthread_mutex_lock(&mutex); //上锁while(ready == 0){pthread_cond_wait(&has_product,&mutex); //线程等待}ready--; //消费consumer_idx++;printf("%5d%s----%d\n", consumer_idx, buf, ready);pthread_mutex_unlock(&mutex); //解锁usleep(100 * 1000);}
}

主方法

void main()
{pthread_t pro_id, con_id;pthread_mutex_init(&mutex, NULL);pthread_cond_init(&has_product, NULL);pthread_create(&pro_id, NULL, producer, "producer");pthread_create(&con_id, NULL, consumer, "consumer");pthread_join(pro_id, NULL);pthread_join(con_id, NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&has_product);
}

以上方法就实现了线程的安全,在生产者有产品的时候通知消费者,消费者完成消费等待生产者

多个生产者与多个消费者

由于上面已经说明原理,这里直接贴出代码

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>int ready = 0;#define CONSUMER_NUM 4 //消费者数量
#define PRODUCER_NUM 3 //生产者数量
pthread_t pids[CONSUMER_NUM + PRODUCER_NUM];pthread_mutex_t mutex; //互斥锁
pthread_cond_t has_product; //条件变量void* producer(void* arg){int *num = (int *)arg;while(1){pthread_mutex_lock(&mutex); //上锁ready++; //生产printf("%5d---product---%d\n", num, ready);pthread_cond_signal(&has_product); //通知消费者,会阻塞pthread_mutex_unlock(&mutex); //解锁usleep(100 * 1000);}
}void* consumer(void* arg){int *num = (int *)arg;while(1){pthread_mutex_lock(&mutex); //上锁while(ready == 0){pthread_cond_wait(&has_product, &mutex); //线程等待}ready--; //消费printf("%5d---consumer---%d\n", num, ready);pthread_mutex_unlock(&mutex); //解锁usleep(100 * 1000);}
}void main()
{pthread_mutex_init(&mutex, NULL);pthread_cond_init(&has_product, NULL);int i;for(i = 0; i < PRODUCER_NUM; i++){ //生产者线程pthread_create(&pids[i], NULL, producer, (void*)i);}for(i = 0; i < CONSUMER_NUM; i++){ //消费者线程pthread_create(&pids[PRODUCER_NUM + i], NULL, consumer, (void*)i);}sleep(10);for(i = 0; i < PRODUCER_NUM + CONSUMER_NUM; i++){pthread_join(pids[i], NULL);}   pthread_mutex_destroy(&mutex);pthread_cond_destroy(&has_product);
}

转载于:https://www.cnblogs.com/cj5785/p/10664651.html

NDK学习笔记-多线程与生产消费模式相关推荐

  1. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  2. python学习笔记——多线程编程

    python学习笔记--多线程编程 基础不必多讲,还是直接进入python. Python代码代码的执行由python虚拟机(也叫解释器主循环)来控制.Python在设计之初就考虑到要在主循环中,同时 ...

  3. NDK学习笔记:FFmpeg解压MP34提取音频PCM(swrContext、swr_alloc_set_opts)

    NDK学习笔记:FFmpeg解压MP34提取音频PCM 承接 FFmpeg解压MP4提取视频YUV ,这次我们需要提取的是音频原始数据PCM.代码流程大同小异,主要区别就是AVFrame->PC ...

  4. NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM(方法签名,CallXXXMethod)

    NDK学习笔记:JNI调用Java层方法创建Native的AudioTrack播放PCM 题目有点复杂,不过确实就是那么回事.这章想记录的内容比较多,先列出来: native static 与 nat ...

  5. NDK学习笔记:一起来变萝莉音!FMOD学习总结(下)

    NDK学习笔记:一起来变萝莉音!FMOD学习总结(下) 一.创建自己的变音demo 上一节我已经能够在AndroidStudio上跑起了fmod的基础教程.还有疑问的同学可以重新阅读跟着来跑一次.这章 ...

  6. NDK学习笔记:FFmpeg音视频同步3(你追我赶,升级ffmpeg/libyuv支持neon)

    NDK学习笔记:FFmpeg音视频同步3 本篇内容说多不多,但如果要说得明明白白的,可能就有点难度了.所以我决定把我的调试过程日志都呈现出来,方便大家理解.继上一篇文末,我们学习到了什么是DTS/PT ...

  7. NDK学习笔记:RtmpPusher之利用rtmpdump推h264/aac码流

    NDK学习笔记:RtmpPusher之利用rtmpdump推h264/aac码流 本篇将是 RtmpPusher 的最后一篇.在之前的3篇文章里,我们已经把原生的视频YUV格式编码成h264,把音频的 ...

  8. Java学习笔记---多线程并发

    Java学习笔记---多线程并发 (一)认识线程和进程 (二)java中实现多线程的三种手段 [1]在java中实现多线程操作有三种手段: [2]为什么更推荐使用Runnable接口? [3][补充知 ...

  9. Java张孝祥视频 学习笔记 多线程

    /*************************************************************************************/ 此博客主要是在观看张孝祥 ...

最新文章

  1. Android studio ButterKnife插件
  2. 把技术卖给不懂技术的人
  3. VueX(Vue状态管理模式)
  4. (九)模型驱动和属性驱动
  5. 《代码大全》代码生成
  6. DDD-Mapper
  7. Xshell 连接CentOS服务器解密
  8. secp256r1 c语言程序,区块链中的数学-secp256k1点压缩和公钥恢复原理
  9. 教你如何批量下载QQ相册或是手机相册里原照片
  10. date time 分开存储如何合并_关于TDateTime的TDate与TTime合并的问题 | 菲菲的家
  11. Js网络视频播放器之VideoJsckplayer(直播拉流rtmp、hls)
  12. Alpha、伪Beta 发布后,夏一鸣的个人感想与体会
  13. Contest2257 - 抗击疫情,从我做起--大中小学生联合训练赛第五十二场
  14. 集成方法,或者叫做组合方法(Ensemble methods)介绍(一)
  15. 基于Gromacs的蛋白分子动力学模拟(RMSD、RMSF及蛋白的回旋半径)
  16. 2020年基因组识别行业研究报告 附下载
  17. 服务器刹车响应时间,驾驶员反应时间及制动响应时间
  18. 文档文件等网页端预览功能
  19. 【米斯特吴】2021年全年系列课程包(Vue/React/Node/大厂面试)
  20. JAVA八种基本数据类型+三种引用数据类型

热门文章

  1. (Java多线程)线程状态
  2. 读书几年收藏的编程利器网站,给大家分享出来
  3. SpringBoot之使用RabbitMQ实现延迟队列
  4. Java源文件的编译、下载、解释和执行
  5. L2-004 这是二叉搜索树吗?-团体程序设计天梯赛GPLT
  6. 错误 未找到引用源_你不理解的EXCEL函数中常见的错误值,都在这里
  7. 华为mate20 android,华为MateRS对比华为mate20RS,终于让安卓手机坐上了头等舱!
  8. 阿里云原生开源大家族加入中科院软件所开源软件供应链点亮计 - 暑期 2021
  9. 重磅 | 阿里开源首个 Serverless 开发者平台 Serverless Devs
  10. win10运行C语言的程序,win10系统运行软件提示应用程序发生异常0xc0000409的具体教程...