2020-04-27

标题嵌入式学习09线程

线程是任务调度和执行的基本单位。
1、线程 VS 进程: 进程:进程空间天然是独立的,因此进程间资源的保护是天然的(现成的),需要重点关心的进程间的通信; 线程:多线程天然的共享进程空间,因此线程数据共享是天然的(现成的),需要重点关心的是资源的保护;
2、为什么会有线程?进程实现多任务的缺点:进程间切换的计算机资源开销很大,切换效率非常低;进程间数据共享的开销也很大;线程和进程的关系:线程是进程的一个执行单元,是进程内的调度实体。比进程更小的独立运行的基本单位;线程也被称为轻量级进程;同一进程的线程共享本进程的地址空间,而进程之间则是独立的地址空间;进程退出,进程中所有线程全部退出;一个进程崩溃后,不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉;所以多进程要比多线程健壮;线程不可能完全替代进程;线程拥有独立的属性(每个线程拥有自己独立的线程ID(TID;每个线程有独立的切换状态;调度优先级;有自己独立的函数栈;自己独立的错误号;每一个线程有自己独立的信号屏蔽字和未决信号集;每个线程有自己独立的tack_struct结构体;)
3 、线程的特点:线程切换的开销很低、实质是函数的切换、线程通信机制简单;
4 、线程的操作: 线程函数是由谁提供的? 非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);功能:把void *(*start_routine) (void *)函数注册为一个线程函数,该函数一旦注册成功,这个函数就以次线程的方式开始并发运行起来,如果不注册的话,这个函数就是一个普通函数。凡是使用pthread_create注册的线程,都是次线程,次线程会和主线程一起并发运行。2)返回值: 成功返回0,失败返回非零错误号。参数:(a)thread存放线程的TID。(b)attr:用于设置线程属性,设置线程属性的目的是为了实现某些特殊功能,如果设置为NULL,表示不设置特有的属性,使用线程默认属性所提供的功能即可。正常情况下,线程默认属性所提供的功能就已经够用了,所以这个参数我们都是设置为NULL。(c)start_routine:要注册为线程的函数地址;函数类型为void () (void *),pthread_create它会把这个函数注册为线程,如果不注册,线程函数就是一个普通的函数。线程函数需要我们自己定义,比如:void *pth_fun(void *pth_arg) { …//线程要做的事情}pth_fun和pth_arg的命名由自己决定。(d)arg:传递给线程函数的参数,这个参数会传递给pth_arg,如果参数很多的话,我们做成一个结构体,然后把结构体变量的地址传过去。如果你不想传递参数的话,你可以设置为NULL。代码实例:创建两个次线程,主线程和两个次线程一起的向同一个文件中写"hello ” “world\n"。
4、线程退出:被动退出: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); 弹栈线程退出处理函数的几种条件: 调用thread_cleanup_pop(!0),主动弹栈; 如果线程是被别人调用pthread_cancel取消的,也会弹栈;如果线程是调用pthread_exit函数退出的,也会弹栈;注:return退出的话,是不会自动弹栈的,要弹栈的话,必须主动调动 thread_cleanup_pop(!0)。
5、线程等待:等待线程的目的:保证线程的退出顺序:保证一个线程退出并且回收资源后允许下一个进程退出;回收线程退出时的资源情况:保证当前线程退出后,创建的新线程不会复用刚才退出线程的地址空间;获得新线程退出时的结果是否正确的退出返回值,这个有点类似回收僵尸进程的wait,保证不会发生内存泄露等问题;函数:int pthread_join(pthread_t thread, void **retval); Q:线程资源为什么不采用进程退出之后一起回收?有些程序(进程)一旦运行后将会长期运行,不会结束,所以次线程在结束时必须回收资源,如果不回收,每结束一个次线程就导致一部分资源被占用,慢慢累积会使得整个进程资源越用越少,最好导致进程崩溃,所以次线程结束时,必须回收次线程资源。
6、线程状态:可结合态:这种状态下的线程是能够被其他进程回收其资源或杀死的;分离态: 这种状态下的线程是不能够被其他线程回收或杀死的;它的存储资源在它终止时由系统自动释放;
7、线程的资源保护机制:
互斥锁 (只能在线程里面用,进程里面是使用信号链来保证互斥。)互斥锁使用的步骤:定义一个互斥锁(变量):pthread_mutex_t mutex;初始化互斥锁:预设互斥锁的初始值:pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 编译时初始化锁位解锁状态加锁解锁进程退出时销毁互斥锁 代码实例同一文件写入数据保持互斥
线程信号量: 线程信号量使用步骤:定义信号量集合:信号量集和需要我们自己定义, 线程信号量集合其实就是一个数组,数组每个元素就是一个信号量。 sem[0]:第一个信号量初始化集合中的每个信号量:初始化信号量的函数(a)函数原型 #include <semaphore.h> int sem_init(sem_t *sem, int pshared, unsigned int value); · 功能:初始化线程信号量集合中的某个信号量,给它设置一个初始值。 · 返回值:成功返回0,失败返回-1,errno被设置。注意:信号量的错误号不是返回的,而是设置到errno中。· 参数: - sem:信号量集合中的某个信号量:如: sem_init(&sem[0], int pshared, unsigned int value);线程信号量集合其实是自定义的一个数组,而进程信号量集合则是通过semget函数创建的。 我们只要把数组定义为全局变量,所有的线程即可共享使用,不像进程信号量,需要semid才能实现共享操作。- pshared:+ 0:给线程使用 + !0:可以给进程使用,不过对于进程来说,我们更多的还是使用进程信号量,因为线程信号量用到进程上时,存在一些不稳定的情况。 - value:初始化值(对于二值信号量来说,要么是1,要么是0。)p、v操作:进程结束时,删除线程信号量集合: 代码实例实现多个线程同步;按照顺序执行条件变量条件变量的作用(线程协同):多线程配合工作时,当线程检测到某条件不满足时就休眠,直到别的线程将条件准备好,然后通过条件变量将其唤醒。(主线程对va变量循环+1,次线程发现va==5时,打印va的值并将va清0,如果va的值!=5就什么都不做。) 注:条件变量需要在互斥锁的配合下才能工作。条件变量的使用步骤:定义一个条件变量(全局变量)由于条件变量需要互斥锁的配合,所以还需要定义一个线程互斥锁。pthread_cond_t初始化条件变量:函数原型 #include <pthread.h>int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);3)使用条件变量:函数:#include <pthread.h>int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); · 功能:检测条件变量cond,如果cond没有被设置,表示条件还不满足,别人还没有对cond进行设置,此时 pthread_cond_wait会休眠(阻塞),直到别的线程设置cond表示条件准备好后,才会被唤醒。4)删除条件变量(也需要把互斥锁删除)函数 #include <pthread.h> int pthread_cond_destroy(pthread_cond_t *cond);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值