线程基础知识:
程序:二进制文件,存放在磁盘上面的文件
进程:正在运行的程序,它处在内存中,一个进程可以被加载无数次
线程:进程的最小活动单元,一个进程中可以有多个线程,至少有一个线程那就是main函数本身
线程的作用:让代码并行运行,而不被阻塞。例如:播放器,播放音乐必定开启了一个线程,理论上播放歌曲时进程会被卡主,即此时UI界面上面的按钮无法点动,整个程序表现为卡死状态,但是实际上播放歌曲时,可以随意点击按钮或者执行其他的操作,这就是多线程导致。
线程的生命周期
就绪:线程即将要运行。可能是刚创建,也可能是刚从阻塞状态唤醒。
运行:线程正在被执行。单处理器中,同一时刻只有一个线程正在运行,多处理器中,同时运行多个线程。
阻塞:线程无法被执行。比如IO阻塞,条件变量阻塞,互斥锁等。
终止:线程函数执行完毕。可能是自然死亡(运行结束return返回),自杀(调用return提前结束,或者调用pthread_exit结束),也可能是他杀(在其他线程调用pthread_cancel结束,或者被kill掉,随进程结束而结束)导致。
线程相关函数
线程创建:pthread_create
获取线程ID:pthread_self
结束线程:pthread_exit, pthread_cancel
等待线程结束:pthread_join
(1)线程创建:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
参数介绍:
thread 线程ID(创建线程时产生)
attr 线程属性(线程优先级,分离状态,调度策略等)
start_routine 线程函数
arg 线程函数的参数
返回值:
0 成功
非0 失败
(2)获取线程ID:
#include <pthread.h>
pthread_t pthread_self(void);
返回值:线程ID
(3)结束线程:
#include <pthread.h>
void pthread_exit(void *retval);
参数:
retval 线程结束之后的返回值
返回值:
无
int pthread_cancel(pthread_t thread);
参数:
thread 线程ID
返回值:
0 成功
非0 失败
(4)等待线程结束:
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval);
参数:
thread 线程ID
retval 线程返回值或状态
线程属性
线程创建时,默认优先级为0,最大为50
pthread_attr_t属性的类型
typedef struct
{
int detachstate; //线程的分离状态
int schedpolicy; //线程调度策略
struct sched_param schedparam; //线程的调度参数,优先级
int inheritsched; //线程的继承性
int scope; //线程的作用域
size_t guardsize; //线程栈末尾的警戒缓冲区大小
int stackaddr_set;
void * stackaddr; //设置线程栈的地址
size_t stacksize; //设置线程栈的大小
}pthread_attr_t;
线程属性相关函数:
初始化:pthread_attr_init
销毁:pthread_attr_destroy
设置优先级:pthread_attr_setschedparam
获取优先级:pthread_attr_getschedparam
优先级结构体如下:
struct sched_param{
int __sched_priority; //所要设定的线程优先级
};
(1)初始化:
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
参数:
attr 线程属性
返回值:
0 成功
非0 失败
(2)销毁:
#include <pthread.h>
int pthread_attr_destroy(pthread_attr_t *attr);
参数:
attr 线程属性
返回值:
0 成功
非0 失败
(3)设置优先级:
#include <pthread.h>
int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
参数:
attr 线程属性
param 线程优先级
返回值:
0 成功
非0 失败
pthread_setschedparam(pthread_t thread, int policy,
const struct sched_param *param);
参数:
thread 线程ID
policy 线程调度策略(SCHED_RR,SCHED_FIFO,SCHED_OTHER )
param 调度优先级
struct sched_param {
int sched_priority; /* Scheduling priority */
};
成功:返回0
非0:失败
(4)获取优先级:
#include <pthread.h>
int pthread_attr_getschedparam(pthread_attr_t *attr, struct sched_param *param);
参数:
attr 线程属性
param 线程优先级
返回值:
0 成功
非0 失败
pthread_getschedparam(pthread_t thread, int *policy,
struct sched_param *param);
参数:
thread 线程ID
policy 线程调度策略(SCHED_RR,SCHED_FIFO,SCHED_OTHER )
param 调度优先级
struct sched_param {
int sched_priority; /* Scheduling priority */
};
成功:返回0
非0:失败
实例一(线程创建实例):
传整型
void *run(void* arg){
int a=*((int*)arg);
while(1){
printf("------- pthread %d\n",a);
sleep(1);
}
}
int main(int argc,char **argv){
//pthread_t id[5];
int i;
for(i=0;i<5;i++){
pthread_t id;
pthread_create(&id,NULL,run,&i); //非阻塞
usleep(200);
}
int b;
scanf("%d",&b);
}
传数组
void *run(void* arg){
//int *p=(int*)malloc(4*7);
int p[7];
memcpy(p,arg,4*7);
int i=0;
while(1){
printf("------- pthread %d\n",p[i++%7]);
sleep(1);
}
//free(p);
}
int main(int argc,char **argv){
int a[]={1,2,3,4,5,6,7};
int i;
//for(i=0;i<5;i++){
pthread_t id;
pthread_create(&id,NULL,run,a); //非阻塞
usleep(200);
//}
//这里需要调用pthread_join函数释放线程资源,创建几个线程 就调用几次
int b;
scanf("%d",&b);
}
//原则,尽快的将arg指向的内存数据拷到线程函数,以免在主函数中将arg指向的值改变。
实例二(线程优先级):
void *run(void* arg){
printf("%d\n", *(int*)arg);
}
int main(int argc,char **argv){
int i;
pthread_t id[5];
pthread_attr_t attr;
pthread_attr_init (&attr);
struct sched_param par={50};
pthread_attr_setschedparam(&attr,&par);
for(i=0;i<5;i++){
if (i==2) pthread_create(&id[i],NULL,run,&i); //创建线程,默认优先级
else pthread_create(&id[i],&attr,run,&i); //创建线程,同时设优先级
usleep(200000);
}
pthread_attr_destroy(&attr);
//这里需要调用pthread_join函数释放线程资源,创建几个线程 就调用几次
int b;
scanf("%d",&b);
}
实例二.1(线程优先级):
void *_ao_test_play_thread(void* arg){
struct sched_param param;
int policy=-1;
struct sched_param s_parm;
s_parm.sched_priority = sched_get_priority_max(SCHED_FIFO);
printf("schedu max %d min %d, current pri=%d\n",sched_get_priority_max(SCHED_FIFO),sched_get_priority_min(SCHED_FIFO), s_parm.sched_priority);
pthread_getschedparam(pthread_self(),&policy,¶m);
printf("-------------- policy = %d, param=%d\n", policy, param.sched_priority );
if (0 == pthread_setschedparam(pthread_self(), SCHED_FIFO, &s_parm)) {
printf("IO Thread #%d using high-priority scheduler!", pthread_self());
}
pthread_getschedparam(pthread_self(),&policy,¶m);
printf("-------------- policy = %d, param=%d\n", policy, param.sched_priority );
while(1) {
sleep(1);
}
}
int main(int argc,char **argv){
pthread_t dmic_thread_id;
ret = pthread_create(&dmic_play_thread_id, NULL, _ao_test_play_thread, NULL);
if (ret != 0) {
IMP_LOG_ERR(TAG, "[ERROR] %s: pthread_create Audio Record failed\n", __func__);
return -1;
}
}
注意:线程默认创建调度策略为SCHED_OTHER(为一般线程,priority为0),改变线程调度策略为SCHED_FIFO或者SCHED_RR(实时线程)之后,线程会比一般线程调度优先级要高,实际测试发现,高负载情况下,实时线程运行要比一般线程更容易运行(这符合实时线程优先级高于一般线程的原理)
线程调度也可参考下面的链接:
https://www.cnblogs.com/xiaotlili/p/3510224.html
https://www.cnblogs.com/zhaoyl/archive/2012/09/04/2671156.html
https://blog.csdn.net/caoyan_12727/article/details/52346729
https://blog.csdn.net/weixin_34199405/article/details/88019539
实例三(线程分离属性):
#include <stdio.h>
#include <error.h>
#include <stdlib.h>
#include <pthread.h>
void* thread_run(void* _val)
{
pthread_detach(pthread_self()); //线程分离之后,不需要调用pthread_join等待线程结束
printf("%s\n", (char*)_val);
return NULL;
}
int main()
{
pthread_t tid;
int tret = pthread_create(&tid, NULL, thread_run, "thread_run~~~~~");
//pthread_join
//线程分离之后,不需要调用pthread_join等待线程结束
int b;
scanf("%d",&b);
}