线程概念
线程线程就是进程的若干个执行流,
因为一个进程在某一时刻只能去做一件事情,有了线程之后,我们可以在同一时间去做不同的事情,比如我正在边利用cmd markdown写博客。边用网易云音乐听音乐,这样多线程的情况下,能给我们带来很多好处。
在系统内核中其实是不存在线程的,linux使用进程模拟线程,线程的实现其实就是多个共享数据代码等信息的进程。所以我们把线程也叫做轻量级进程。
进程常常用来分配资源,线程用来调度资源。
线程中共享的资源:
- 文件描述符表
- 信号处理方式
- 当前工作目录
- uid,gid
线程中独立的资源:
- 线程id(tid)
- 线程的上下文信息,寄存器信息,PC制作,栈指针
- 栈空间
- errno变量
- 信号屏蔽字
- 调度优先级
- 线程私有数据
线程的函数大部分都放在pthread.h的头文件当中,并且在编译的时候我们需要注意的是加上-lpthread选项,这样就会去动态链接动态库。
线程控制
线程的控制
- 创建线程
线程的创建使用线程创建函数。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
需要注意的是线程创建函数的参数,第三个参数start_rountine就是新创建的线程所要跑的函数,arg是你传入的参数。
因为在linux环境下,系统内部其实是不存在线程的,我们一般说线程叫做轻量级进程,线程创建以后,两个线程的pid和ppid都是一样的。操作系统会为之提供一个线程的tid,这个tid我们可以通过一个函数获取:
pthread_t pthread_self(void);
需要注意的是pthread_self所获取到的是相对于进程的线程控制块的首地址,只是用来描述统一进程当中的不同的线程。而真正的内核当中的线程ID,对于多线程进程来说,每个tid实际是不一样的。
另外,在linux当中如果你要查询系统中的线程,也有一条命令:ps -aL
- 线程等待
在进程当中我们提到过,如果我们当子进程结束以后,这个时候需要让父进程得到信息,然后由父进程去进行资源的回收,以及后续的处理,所以我们要确保子进程先结束,然后父进程再结束,否则会出现僵死状态,当值内存泄漏的问题。所以进程当中我们提到了wait和waitpid函数。
线程当中同样有上述的问题,当你的新线程结束,你的主线程也是需要等待,然后回收新线程的资源及其他信息。这样就能确保内存不泄露。所以这里使用一个函数pthread_join函数来进行等待。
int pthread_join(pthread_t thread, void **retval);
thread就是线程号,retval是一个二级指针,用途是用来获取线程的退出码。
- 终止线程
线程可以等待,当然也可以终止。终止线程可以使用三种方法:
方法 | |
---|---|
1 | 使用return返回,在主线程当中执行的时候类似于exit,直接结束进程 |
2 | 使用pthread_exit函数,终止自己的线程 |
3 | 使用pthread_cancel函数,可以用来终止统一进程的线程 |
void pthread_exit(void *retval);
pthread_exit用来终止线程自身,参数是返回的错误码,想要获得这个错误码,可以通过pthread_join来获得。
int pthread_cancel(pthread_t thread);
pthread_cancel参数为要终止线程的tid,
分离线程和结合线程
线程是可结合或者是分离的。
一个可结合的新线程需要被主线程回收资源和杀死。一个可结合的线程会容易出现类似于僵尸进程的问题,一般我们采用join来等待。否则就会出现主线程无法获取到新线程信息,无法回收新线程的资源,这样就会造成内存泄漏的问题。我们在默认的情况下,线程是可结合的。<