1.线程为什么能弥补进程的缺点
为什么线程切换的开销很低
但是使用多线程来实现多线任务时,由于线程本质上它只是程序(进程)的一个函数,只不过线程函数
与普通函数的区别是,普通函数时单线的运行关系,而线程函数被注册为线程后,是多线并发运行。
对于普通函数来说,只有相互调动时才会涉及函数间的切换,但是对于线程函数来说,只要运行时间片到了就会切换,但是不管是那种函数间的切换,进程自己函数的切换只是进程内部的事情,不涉及进程间切换, 就省去了进程间切换巨大销。
疑问:线程切换不一样需要开销?
刚说过,线程的切换其实就是函数间的切换,函数切换当然也需要开销,但是这些开销相比进程间切换的开销来说,已经非常小了。
为什么线程间数据通信的开销很低
线程的本质就是函数,请问大家函数之间如果想要数据共享(通信)的话,应该怎么办?
函数间通信有两种方式:
是不是有了线程后,进程就不需要了?
线程是不可能完全替代掉进程的,只有在多线任务时会替代进程,但是运行新程序的时,我们还是必须创建子进程。
线程的本质是函数,函数运行需要内存空间,这个内存空间怎么来,事实上线程运行的内存空间就是进程的内存空间,因此线程运行时必须依赖于进程的存在,如果没有进程所提供的内存空间这个资源,线程根本无法运行。
换句话说,线程作为函数,只是进程的一个部分而已,线程是不可能脱离进程而独立存在。
对于进程中的所有函数来说(包括线程函数),进程中几乎所有的资源都是共享的,比如打开的文件描述,所有可以被调用的子函数,进程的当前工作目录,进程uid、gid,进程PID等等。
线程自己独立的属性
(1)每个线程拥有自己独立的线程ID(TID)
(2)每个线程有独立的切换状态
(3)有自己独立的函数栈
(4)自己独立的错误号
(5)每一个线程有自己独立的信号屏蔽字和未决信号集
(6)每个线程有自己独立的tack_struct结构体
什么时候使用多线程和多进程
线程
程序涉及多线任务时,使用线程。
进程
程序涉及到运行新程序时,必须使用多进程,不过一般来说,如果不是大型软件和框架的话,我们的程序并不需要执行新程序。
2.线程控制相关的函数
线程控制函数有: pthread_create、pthread_join、 pthread_detach、pthread_cancel、pthread_exit等。
线程函数是由谁提供的
进程控制的fork、exec等函数都是由os系统提供的,那线程函数是由谁提供的呢?
原本线程函数也可以完全由OS来实现,但是后来为了不给OS增加负担,同时也为了提高线程的灵活性,后来的线程就不在由OS提供,而是由单独的线程库来提供,不过线程库在实现时,也是调用了相应的系统API的,也就是说线程的核心实现也是离不开OS支持的。
线程库
(1)c线程函数
由c线程库提供,注意这个c线程库并不是C标准库,而是POSIX C库的一部分
posix的c线程库,是由美国一些标准组织制定,并有相应c语言和unix、Linux维护团队开发的。 、
(2)java、c++、c#的线程函数
这些语言的线程库,是由这些语言的维护团队来开发的。
线程库和OS系统API的关系
线程库函数实际上也是封住OS的相应API来实现的,如果线程库运行在Linux这边的话,线程库其实就是 通过调用Linux的clone()等系统函数实现的。
将线程函数注册为线程时,其实就是通过调用这类系统API,然后去模拟我们的进程来实现的,正是因为是模拟进程来实现的,所以线程函数才能进程一样,一起被并发运行。
c线程控制函数
线程库和函数手册的安装
sudo apt-get install glibc-doc :安装线程库 sudo apt-get install manpages-posix-dev:安装线程库的函数手册
pthread_create
#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
需要强调的地方
pthread_cancel
#include <pthread.h> int pthread_cancel(pthread_t thread);
pthread_exit
#include <pthread.h> void pthread_exit(void *retval);
pthread_self
#include <pthread.h> pthread_t pthread_self(void);
pthread_join
#include <pthread.h> int pthread_join(pthread_t thread, void **retval);
疑问:线程所用内存资源本身就是来自于进程空间,既然进程结束后,整个进程的资源都会被回收掉,次线程结束时干嘛要回收资源,等进程结束后一并回收不就得了吗?
答:有些程序(进程)一旦运行后将会长期运行,不会结束,所以次线程在结束时必须回收资源,如果不回收,每结束一个次线程就导致一部分资源被占用,慢慢累积会使得整个进程资源越用越少,最后导致进程崩溃,所以次线程结束时,必须回收次线程资源。
pthread_detach
#include <pthread.h> int pthread_detach(pthread_t thread);
注册线程退出处理函数
可以注册进程退出处理函数,其实也可以注册线程退出处理函数,线程在退出时会自动调用,实现线程的扫尾处理
void pthread_cleanup_push(void (*routine)(void *), void *arg); void pthread_cleanup_pop(int execute);
功能
弹栈线程退出处理函数的几种条件
线程的属性设置
可以设置的线程属性有,
- · 设置绑定属性
- · 设置分离属性
- · 设置线程堆栈属性
- · 设置线程调度优先级属性 等等
如果我们什么属性都不设置,那么线程使用的就是默认属性,事实上默认属性所提供的功能就已经足够我们使用了
将线程分离有两种方法:
· 调用pthread_detach函数实现
· 通过设置分离属性实现这里介绍第二种:分离属性设置的步骤
线程的资源(数据)保护