一.线程
概念:线程是进程中的一条执行流,是CPU执行调度的基本单位.
线程是进程中的一条执行流,一个进程中可以有多个流程.然而Linux下的线程执行流是通过pcb实现的,且一个进程中可能有多个pcb,并且这些pcb共享同一个进程中的大部分资源,相较于传统pcb更加轻量化,因为线程也被称为轻量级进程.
Linux环境下:
- 线程是CPU执行调度的基本单位
- 进程是系统进行资源分配的基本单位
- 线程共享进程数据,但也要拥有自己的一部分数据
线程之间的独有与共享:
共享:虚拟地址空间(代码段和数据段),文件描述符表,信号处理方式,工作路径
独有:栈,寄存器,信号屏蔽字,优先级,errno,线程标识符
二.线程控制:
(1).线程的创建:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
thread:用于获取创建的线程ID
attr:线程属性 通常设置为NULL
start_routine:线程的入口函数
arg:就是通过线程入口函数给线程传递的参数
返回值:成功返回0 失败返回非0
(2).线程的终止:
线程终止的三种方式:
- 线程入口函数中执行return(线程入口函数运行完毕,线程就会退出)
- 使用库函数 pthread_exit
#include <pthread.h>
void pthread_exit(void *retval);
retval:作为线程的退出返回值
- 使用库函数 pthread_cancel
#include <pthread.h>
int pthread_cancel(pthread_t thread);
tid:指定的线程id
取消一个线程,传入谁的id就会退出谁,线程的退出返回值:PTHREAD_CANCELED
主线程退出并不会导致进程退出(进程资源被释放),只有所有线程退出了,进程才会退出.
(3).线程的等待
线程默认情况下退出后,资源不会被回收,需要被其它线程等待,获取退出线程的返回值,释放资源.
#include <pthread.h>
int pthread_join(pthread_t thread, void **retval); //阻塞接口
在线程属性中,有一个分离属性(默认值是joinable),处于joinable状态的线程,退出后不会自动释放资源,需要被等待
(3).线程的分离
设置线程的分离属性为detach属性,处于detach属性的线程,退出后自动释放资源,不需要被等待.
#include <pthread.h>
int pthread_detach(pthread_t thread);
注意:只有程序员不关心线程返回值,并且也不想等待线程退出的时候,才会分离线程.
三.线程与进程的区别
进程: 一个在内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程可以有多个线程
线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行.一个进程至少有一个线程,一个进程可以运行多个线程.
- 根本区别: 进程是操作系统资源分配的基本单位,线程是CPU执行调度的基本单位
- 资源开销:由于进程具有独立性(都有各自的虚拟地址空间),同一进程中的线程共享虚拟地址空间等,每个线程都有自己独立的运行栈和程序计数器.因此,进程的创建和销毁要比线程的成本高.并且进程之间的切换成本也要高于线程. 进程间通信的方式比线程更加复杂.
- 包含关系: 一个线程只能属于一个进程,而一个进程可以拥有多个线程.
- 内存分配: 同一个线程中的所有线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
- 影响关系: 一个进程崩溃后,在保护模式下不会对其它进程产生影响.而一个线程崩溃其它的线程也会受到影响,整个进程都会崩溃,所以多进程比多线程更健壮
- 执行过程:每个独立的进程都有程序运行的入口,顺序执行和程序出口.但是线程不能独立执行,必须依存于进程
四.多线程/进程进行多任务的优缺点
多线程进行多任务的优缺点:
优点:
- 共享虚拟地址空间,因此线程间通信更加灵活(除了可以通过进程间通信方式,还可以通过全局变量,函数传参)
- 线程的创建和销毁的成本更低
- 同一个进程中的线程切换成本更低
缺点:
- 健壮性低,有些系统调用和异常是针对整个进程产生效果(例如exit函数,使整个进程退出)
多进程进行多任务的优缺点:
优点:
- 由于各自进程都有自己的进程虚拟空间,所以各个程序之间的运行不会互相干扰,运行稳定
- 子进程崩溃,不会影响父进程.(反之,同理)
- 多个进程可以充分利用多核CPU,并行的运行,不用担心对程序结果造成二义
缺点:
- 进程具有独立性,所以不同进程之间的数据交互需要用到进程间通信
- 进程创建和销毁的成本更高,占用的资源更多
- 子进程退出需要父进程进行等待,否则会造成资源泄漏(线程可以设置分离属性,不需要等待释放资源)
- 多进程程序中进程之间的切换成本更高