线程
概述
线程(英语:thread)是操作系统能够进行运算调度的最小单位(程序执行流的最小单元)。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
线程和进程的异同
包含关系:
每个进程至少有一个线程,这些线程共享进程的所有资源,线程本身只拥有自己的栈空间。
控制块:
线程是TCB,进程是PCB。
基本单位:
进程——资源分配的最小单位,线程——程序执行的最小单位。(面试)
状态:
进程和线程一样都拥有阻塞态、就绪态、运行态。
在Linux中的编译指令:
进程使用 gcc xxx.c -o xxx
线程使用 gcc xxx.c -lpthread -o xxx
如何选择使用进程还是线程
①需要频繁创建销毁的优先使用线程,因为对进程来说创建和销毁一个进程代价是很大的。
②切换频繁和耗时操作用线程,因为程的切换速度快,应用程序的响应快。
③多机分布的用进程,多核分布用线程,因为对 CPU 系统的效率使用上线程更占优。
④并行操作时使用线程,如 C/S 架构的服务器端并发线程响应用户的请求。
⑤需要更稳定安全时,适合选择进程;需要速度时,选择线程更好。
函数
获取进程自身ID pthread_self
头文件:
#include <pthread.h>
函数原型:pthread_t pthread_self(void);
返回值:进程自身的 ID。
pthread_t pid = pthread_self();
创建线程 pthread_create
头文件:
#include <pthread.h>
函数原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
参数介绍:
thread: 子线程ID。
attr:分离属性与非分离属性。
void *(*start_routine) (void *):线程服务函数。
arg:线程函数的参数
返回值:成功返回 0 失败返回 error。
分离与非分离属性:
分离:分离一个正在运行的线程并不影响进程,仅仅是通知当前系统该线程结束时,其所属的资源可以回收;分离的线程在终止时会保留它的虚拟内存,包括他们的堆栈和其他系统资源,有时这种线程被称为“僵尸线程”。
非分离:如果线程具有非分离属性,进程终止时会被立刻回收将释放掉所有线程。终止时未释放的系统资源和进程资源,不保存线程返回值的内存空间、堆栈、寄存器等。
void * pthread_fun(void * arg)
{}
pthread_t pid;
pthread_create(&pid,NULL,pthread_fun,NULL);
退出线程 pthread_exit
头文件:
#include <pthread.h>
函数原型:void pthread_exit(void *retval);
参数介绍:
retval:返回值地址。
void * pthread_fun(void * arg)
{
pthread_exit(NULL);
}
线程等待 pthread_join
头文件:
#include <pthread.h>
函数原型:int pthread_join(pthread_t thread, void **retval);
参数介绍:
thread:等待线程的 ID
Retval:返回值。
返回值:成功返回 0,失败返回 error。
pthread_join( pid , NULL );
四种线程模型
注:下面图中的pc为pthread_create简写。
1 )单线程
执行顺序:
main → fun1 → fun2 → fun3 → mainend
此模型中只有一个线程,所有的函数线程id相同。
2 )单线程
执行顺序:
main → fun1 → fun2 → fun1end → fun3 → mainend
此模型中只有一个线程,所有的函数线程id相同。
3 )双线程
执行顺序:
main → fun2 → fun3 → mainend
↓pc(fun1)
fun1 → fun1end
此模型中有俩个线程。
4 )三线程
执行顺序
main → fun3 → mainend
↓pc(fun1)
fun1 → fun1end
↓pc(fun2)
fun2 → fun2end
此模型中有三个线程。