嵌入式课堂笔记09

信号:是一种向进程发送通知,告诉其某件事情发生了的一种简单通信机制
信号的产生:另一个进程发送信号
内核发送信号
底层硬件发送信号
段错误
嵌入式课堂笔记09_第1张图片
在这里插入图片描述
嵌入式课堂笔记09_第2张图片
常用信号:SIGABRT 6 终止进程,调abort函数时产生
SIGALRM 14 超时,调用alarm函数时产生
SIGBUS 7 硬件故障
SIGCHLD 17 子进程状态改变
SIGINT 2 终止进程(ctrl+c)
SIGIO 29异步通知信号
SIGKILL 9无条件终止一个进程,不可以被捕获或忽略
SIGPIPE 13写没有读权限的管道文件时
SIGFPE 8 轮询实践,涉及POLL机制
SIGQUIT 3 终止进程(ctrl+\)
SIGSEGV 11 无效存储访问(指针错误)
SIGTERM 15 终止,kill PID时,默认发送的就是这个信号
SIGUSR1 10 用户定义信号1
SIGUSR1 12 用户定义信号2
信号发送
int kill(pid_t pid,int sig);
int rasie(int sig);//给当前进程发送信号
unsigned int alarm(unsigned int seconds);//给当前进程发送信号
void abort();//给当前进程发送信号
嵌入式课堂笔记09_第3张图片
嵌入式课堂笔记09_第4张图片
调用alarm函数会十秒后产生SIGALRM语句,并且终止进程。若加入while语句,则可以停止十秒,相当于制定了一个闹钟。若加入一个pause函数,会令目前的进程暂停(进入睡眠状态), 直到被信号(signal)所中断。
pause()进程挂起
信号处理方式:忽略、执行用户需要执行的动作(捕获)、默认处理
信号处理API:
#include
typedef void(*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);//设置某个信号的处理方式
嵌入式课堂笔记09_第5张图片

(a)忽略:SIG_IGN
(b)默认:SIG_DFL
线程概述:
(1)线程是任务调度和执行的基本单位。
(2)为什么会有线程?
①进程实现多任务的缺点:
a.进程间切换的计算机资源开销很大,切换效率非常低;
OS是通过虚拟内存机制来实现进程空间独立的,进程在并发运行时需要相互间的切换,切换时必然需要涉及虚拟内存机制的控制,但是虚拟内存机制比较复杂,所以在进行进程间切换时,会耗费高昂的cpu、缓存(cache)、内存等计算机资源,也非常耗费切换时间。
b.进程间数据共享的开销也很大。
当程序涉及多进程时,往往会涉及到进程间的通信,但是由于进程空间的独立性,OS提供了各种各样的通信机制,这些通信机制共同原理就是,通过OS来转发进程间的数据,但是调用OS提供的这些通信机制的函数时,这些OS函数的运行也是需要消耗相当cpu、内存等计算机资源的,同时也很耗费时间。
②线程和进程的关系:
a.线程是进程的一个执行单元,是进程内的调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程;
b.同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间;
c.进程退出,进程中所有线程全部退出;
d.一个进程崩溃后,不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉,所以多进程要比多线程健壮;
e.线程不可能完全替代进程;
f. 线程拥有独立的属性:
每个线程拥有自己独立的线程ID 每个线程有独立的切换状态;
调度优先级;
有自己独立的函数栈;
自己独立的错误号;
每一个线程有自己独立的信号屏蔽字和未决信号集;
每个线程有自已独立的tack struct结构体。
线程的特点:线程切换的开销很低——实质是函数的切换
线程通信机制简单——全局变量
线程操作:
①线程函数是由谁提供的?
非OS,而是线程库libpthread.a/.so
线程控制函数有:pthread_create、pthread_join、pthread__detach、pthread_cancel、pthread_ exit等
②线程库和函数手册的安装
sudo apt-get install glibc-doc:安装线程库
sudo apt-get install manpages-posix-dev:安装线程库的函数手册
③线程创建:
int pthread_create(pthread_t*thread,const pthread_attr_t * attr,void *(*start_ routine)(void *),void *arg);
代码实例:创建两个次线程,主线程和两个次线程一起的向同一个文件中写"hello”“world\n”
④线程退出
被动退出: int pthread_.cancel(pthread_t thread);
主动退出:void pthread_ exit(void retval); return返回。
注册线程退出处理函数:
void pthread_ cleanup_ push(void ( routine)(void *), void * arg);
void pthread_ cleanup_ pop(int execute);
单线程退出处理函数的几种条件:
如果线程是调用pthread_ exit函数退出的,也会弹栈
如果线程是被别人调用pthread_.canceI取消的,也会弹栈
注: return退出的话,是不会自动弹栈的,要弹栈的话,必须主动调动thread_ cleanup_ pop(!0)。
⑤线程等待
等待线程的目的:
保证线程的退出顺序:保证一个线程退出并 且回收资源后允许下一个进程退出;
回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间;
获得新线程退出时的结果是否正确的退出返回值,这个有点类似回收僵尸进程的wait,保证不会发生内存泄露等问题。
int pthread_join(pthread_t thread, void **retval);线程资源为什么不采用进程退出之后一起回收?
⑥线程状态
可结合态:这种状态下的线程是能够被其他进程回收其资源或杀死的;
分离态:这种状态下的线程是不能够被其他线程回收或杀死的:它的存储资源在它终止时由系统自动释放;
默认情况下,线程被创建成可结合的!
如何避免多线程退出导致的内存泄漏?
每个可结合线程需要显示的调用pthread_join回收
将其变成分离态的线程;线程分离函数–pthread_ detach
线程VS进程
(1)进程:进程空间天然是独立的,因此进程间资源的保护是天然的(现成的),需要重点关心的进程间的通信
(2)线程:多线程天然的共享进程空间,因此线程数据共享是天然的(现成的),需要重点关心的是资源的保护
线程的资源保护机制:
①互斥锁
互斥锁使用步骤:1)定义一个互斥锁(变量)pthread_mutex_t mutex;
2)初始化互斥锁:预设互斥锁的初始值
pthread_mutex_t mutex=PTHREAD_MUTEX_INTIALIZER
编译时初始化锁位解锁状态
3)加锁解锁
4)进程退出时销毁互斥锁
②线程信息量
线程信息量使用步骤:1)定义信号量集合
2)初始化集合中的每个信号量
3)p、v操作
4)进程结束时,删除线程信号量集合
③条件变量(作用:线程协同)——主线程对va变量循环+1,次线程发现va==5时,打印va的值并将va清零,如果va的值!=5就什么都不做
(注:条件变量需要在互斥锁的配合下才能工作)
条件变量的使用步骤:1)定义一个条件变量(全局变量)由于条件变量需要互斥锁的配合,所以还需要定义一个线程互斥锁——pthread_cond_t
2)初始条件变量
3)使用条件变量
4)删除条件变量,也需要把互斥锁删除
嵌入式课堂笔记09_第6张图片
嵌入式课堂笔记09_第7张图片
嵌入式课堂笔记09_第8张图片
例:时序出现问题
嵌入式课堂笔记09_第9张图片
嵌入式课堂笔记09_第10张图片
嵌入式课堂笔记09_第11张图片
加锁后
嵌入式课堂笔记09_第12张图片
嵌入式课堂笔记09_第13张图片
嵌入式课堂笔记09_第14张图片
线程协同
嵌入式课堂笔记09_第15张图片
嵌入式课堂笔记09_第16张图片
嵌入式课堂笔记09_第17张图片
在这里插入图片描述
对于线程和进程是有区别的,进程是资源分配的最小单位,线程是任务调度的最小单位;每个进程拥有独立的地址空间,多个进程共享进程地址空间。在需要频繁创建和销毁时,需要大量计算时使用线程。高性能交易服务器中间件主张多进程,强相关的处理要用线程,弱相关的处理用进程,多机分布的用进程,多核分布的用线程。

你可能感兴趣的:(嵌入式课堂笔记09)