嵌入式linux设置进程资源分配,嵌入式Linux开发:线程、多线程

学习视频

快速浏览

第一部分:线程的基础知识

1.线程的概念

2.线程的特点

3.进程与线程的关系

4.为什么要用线程

第二部分: Linux线程的实现

1.编译

2.线程标识

3.线程创建(龟兔赛跑例程)

4.线程终止

5.线程清理和控制

6.设置和获得分离属性

第三部分:Linux线程的互斥和同步

互斥锁

读写锁

条件变量

线程信号量

死锁

第一部分:线程的基础知识

1.线程的概念

线程是进程的一个执行单元,是进程内的调度实体。

线程按照其调度者可分为用户级线程和内核级线程两种

用户级线程:主要解决的是上下文切换的问题,其调度过程由用户决定。

内核级线程:由内核调度机制实现

现在大多数操作系统都采用用户级线程和内核级线程并存的方法。

用户级线程要绑定内核级线程运行,–个进程中的内核级线程会分配到固定的时间片,用户级线程分配的时间片以内核级线程为准。

默认情况下用户级线程和内核级线程是一对一,也可以多对

这样实时性就会比较差。

当cpu分配给线程的时间片用完后但线程没有执行完毕,此时线程会从运行状态返回到就绪状态,将cpu让给其它线程使用。

2.线程的特点

线程是比进程更小的独立运行的基本单位。线程也被称为轻量级进程

同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间

进程退出,进程中所有线程全部退出

一个进程崩溃后,不会对其它进程产生影响;但是一个线程崩溃后,整个进程就崩溃,所以多进程比多线程健壮

线程不可能完全替代进程

线程拥有自己独立的属性(线程ID(TID),切换状态,调度优先级,函数栈,错误号,信号屏蔽字和未决信号集,task_ struct结构体)

线程的开销比较低,实际上是函数的切换

线程的通信简单:全局变量

linux线程支持 是基于库的,库的优点是可以跨平台

3.进程与线程的关系

线程和进程的关系是:线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一用户内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。

一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如cpu、内存、文件等等)。而将线程分配到某个cpu上执行。

7523876e08a4fef6188e0f791b3326f3.png

4.为什么要用线程

因为线程和进程比起来很小,所以相对来说,线程花费更少的CPU资源。

在操作系统设计上,从进程演化出线程,最主要的目的就是更好地支持多处理器,并且减小进程上下文切换的开销。

第二部分: Linux线程的实现

1.编译

首先在项目上右击,属性,依次点击

C/C++ Build -> Settings ->右边Tool Settings -> 下面GCC C Linker

在右上侧Command中添加 -lpthread

9e8c8e3375b32c6e639a8fefd9fcef3d.png

2.线程标识

每个进程内部的不同线程都有自己的唯一标识(ID)

线程标识只在它所属的进程环境中有效

线程标识是 pthread_t 数据类型

#include

int pthread equal(pthread_t, pthread_t);

//返回:相等返回非0,否则返回O

pthread_t pthread_self(void);

//返回:调用线程的线程ID

3.线程创建(龟兔赛跑例程)

tidp: 线程标识符指针

attr: 线程属性指针

start_rtn:线程运行函数的起始地址

arg:传递给线程运行函数的参数

新创建线程从 start_rtn 函数的地址开始运行

不能保证新线程和调用线程的执行顺序

#include

int pthread_create(pthread t *restrict tidp,

const pthread_attr_t *restrict attr,

void *(*start_rtn)(void*), void *restrict arg);

//返回:成功返回0,否则返回错误编号

//创建线程示例--->龟兔赛跑(初级版)

#include

#include

#include

#include

#include

//定义线程运行函数

void *th_fn(void *arg){

int distance=(int)arg;

int i;

for(i=1;i<=distance;i++){

printf("%lx run %d\n",pthread_self(),i);

int time=(int)(drand48()*10000);

usleep(time);//微秒

}

return (void*)0;

}

int main(void)

{

int err;//存储错误码

pthread_t rabbit,turtle;//定义兔子/乌龟线程

//创建rabbit线程

if((err=pthread_create(&rabbit,NULL,

th_fn,(void *)50))==-1){

perror("pthread_creat error");

}

//创建turtle线程

if((err=pthread_create(&turtle,NULL,

th_fn,(void *)50))==-1){

perror("pthread_creat error");

}

//主控线程调用pthread_join(),自己会阻塞

//直到rabbit和turtle线程结束方可运行

pthread_join(rabbit,NULL);

pthread_join(turtle,NULL);

//sleep(10);

printf("主控线程的ID:%lx\n",pthread_self());

printf("结束\n");

return 0;

}

//创建线程示例--->龟兔赛跑(升级版)

#include

#include

#include

#include

typedef struct{

char name[20];

int time;

int start;

int end;

}RaceArg;

void *th_fn(void *arg){

RaceArg *r=(RaceArg *)arg;

int i=r->start;

for(;i<=r->end;i++){

printf("%s (%lx) running %d\n",r->name,pthread_self(),i);

usleep(r->time);

}

return (void *)0;

}

int main(void){

int err;

pthread_t rabbit,turtle;

RaceArg r_a={"rabbit",(int)(drand48()*10000000),2,16};

RaceArg t_a={"turtle",(int)(drand48()*1000),1,15};

if((err=pthread_create(&rabbit,NULL,

th_fn,(void *)&r_a))==-1){

perror("pthread_create error");

}

if((err=pthread_create(&turtle,NULL,

th_fn,(void *)&t_a))==-1){

perror("pthread_create error");

}

pthread_join(rabbit,NULL);

pthread_join(turtle,NULL);

//sleep(5);

printf("主控线程ID:%lx\n",pthread_self());

printf("finish");

return 0;

}

806748ccebb3e16081d00a39e1f2bc9e.png

4.线程终止

主动终止

1.线程的执行函数中调用return语句

2.调用pthread_exit()

被动终止

线程可以被同一进程的其他线程取消,其它线程调pthread_cancel(pthid)

#include

int pthread_cancel(pthread_ t tid);

void pthread_exit(void *retval);

int pthread_join(pthread_t th, void **thread_return);//特殊

返回值:成功返回0,否则返回错误编号

pthread_cancel

线程可以被同-进程的其他线程取消,tid为被终止的线程标识符。

pthread_exit

retval: pthread_exit调用者线程的返回值,可由其他函数和pthread_join来 检测获取。

线程退出时使用函数pthread_exit是线程的主动行为。

由于一个进程中的多个线程共享数据段,因此通常在线程退出后,

退出线程所占用的资源并不会随线程结束而释放。所有线程想结束后马上释放资源,就需要在主控线程中调用pthread_join函数来等待线程结束,类似于wait系统调用。

pthread_join

th:被等待线程的标识符

thread_return:用户定义指针,用来存储被等待线程的返回值

调用此方法的线程会被阻塞

//pthread_join等待线程结束并返回主线程值示例

#include

#include

#include

typedef struct{

int d1,d2;

}Arg;

void *th_fn(void *arg){

Arg *r=(Arg *)arg;

return (void *)(long)(r->d1+r->d2);

}

int main(void){

int err;

int *result;

int result2;

pthread_t th;

Arg r={20,50};

if((err=pthread_create(&th,NULL,th_fn,(void *)&r))==-1){

perror("pthread_create error");

}

//方法一

pthread_join(th,(void **)&result);

printf("result is %d\n",(int)result);

//方法二

//pthread_join(th,(void *)&result2);

//printf("result is %d\n",result2);

printf("主线程结束");

return 0;

}

方法一原理图

82db3ab2d1fdd3561ba662f638dc2345.png

5.线程清理和控制

#include

void pthread_cleanup_push(void (*rtn)(void *), void* arg);

void pthread_cleanup_pop(int execute);

返回:成功返回0,否则返回错误编号

这一组函数是成对出现和使用的

参数

rtn:清理函数指针

arg:调用清理函数传递的参数

execute:值1时执行线程清理函数,值0时不执行线程清理函数。

触发线程调用清理函数的动作

调用pthread_exit

响应取消请求

用非零execute参数调用thread_cleanup_pop时

#include

#include

#include

//定义线程清理函数

void clean_fun(void *arg){

char *s=(char *)arg;

printf("clean_func: %s\n",s);

}

void *th_fn(void *arg){

int execute=(int)arg;

pthread_cleanup_push(clean_fun,"first clean func");

pthread_cleanup_push(clean_fun,"second clean func");

printf("thread running %lx\n",pthread_self());

pthread_cleanup_pop(execute);

pthread_cleanup_pop(execute);

return (void *)0;

}

int main(void){

int err;

pthread_tth1,th2;

if((err=pthread_create(&th1,NULL,th_fn,(void *)1))==-1){

perror("pthread_creat error");

}

pthread_join(th1,NULL);

printf("th1(%lx) finished\n",th1);

if((err=pthread_create(&th2,NULL,th_fn,(void *)1))==-1){

perror("pthread_creat error");

}

pthread_join(th2,NULL);

printf("th2(%lx) finished\n",th2);

return 0;

}

6.设置和获得分离属性

#include

int pthread_attr_getdetachstat(const pthread_attr_t *restrict attr,int *detachstate);

int pthread_attr_setdetachstat(const pthread_attr_t *attr,int detachstate);

返回:成功返回0,出错返回错误编号

detachstate取值

PTHREAD CREATE JOINABLE(默认值)正常启动线程

PTHREAD_ CREATE DETACHED以 分离状态启动线程

以默认方式启动的线程,在线程结束后不会自动释放占有的系统资源,要在主控线程中调用pthread_join()后才会释放。

以分离状态启动的线程,在线程结束后会自动释放所占有的系统资源。

分离属性在网络通讯中使用的较多。

第三部分:Linux线程的互斥和同步

互斥锁

读写锁

条件变量

线程信号量

死锁

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值