Linux服务器开发——详解线程


Linux服务器开发——详解线程文章插图
一、概念线程定义

  • 一个线程指的是进程中一个单一顺序的控制流 , 也称为轻量进程(LWP)
  • 一个进程可以有很多线程 , 每个线程并行执行不同的任务
  • 线程会拥有自己的堆栈(不共享) , 但是它与同一进程中的多个线程将共享该进程中的全局变量、文件描述符等系统资源
进程和线程的区别
  • 根本区别:进程是最小的分配资源的单位 , 线程是最小的执行单位 。
  • 通信机制:对于不同的进程之间 , 它们具有独立的数据空间 , 数据进行传递只能通过通信的方式进行 , 方式不仅耗时 , 而且不方便 。 但同一进程下的线程之间共享数据空间 , 通信很方便且安全
  • 内存分配:系统在运行的时候会为每个进程分配不同的内存空间 , 而线程除了CPU外 , 不会再分配空间 , 而是使用进程的资源空间
  • 从属关系:线程是进程的一部分 , 进程一旦结束 , 所有线程都结束
线程的共享资源
  • 文件描述符表
  • 每种信号的处理方式
  • 当前工作目录
  • 用户ID和组ID
  • 内存地址空间
线程的非共享资源
  • 线程id
  • 处理器现场和栈指针(内核栈)
  • 独立的栈空间(用户空间栈)
  • errno变量
  • 信号屏蔽字
  • 调度优先级
线程优缺点优点
  • 提高程序的并发性
  • 开销小 , 不用重新分配内存
  • 通信和共享数据方便
缺点
  • 线程不稳定 , linux线程的概念比信号还晚才出来 , 库函数实现 , 需要链接 -lpthread
  • 多线程调试比较困难(gdb支持不好)
  • 线程无法使用unix经典事件 , 例如信号
线程标识符
  • 像每个进程有一个进程ID一样 , 每个线程也有一个线程ID
  • 进程ID在整个系统中是唯一的 , 但线程不同 , 线程ID只在它所属的进程环境中有效
  • 线程ID用pthread_t数据类型来表示
Linuxc/c++服务器开发高阶视频学习资料后台私信【架构】获取更多视频内容包括C/C++ , Linux , Nginx , ZeroMQ , MySQL , Redis , MongoDB , ZK , 流媒体 , P2P , K8S , Docker , TCP/IP , 协程 , DPDK多个高级知识点分享 。
Linux服务器开发——详解线程文章插图
二、线程原语因为Linux多线程是有库函数实现的 , 需要添加头文件#include, 且编译的时候需要链接 -lpthread 库
线程创建#include int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);参数
  • pthread_t *thread:传递一个pthread_t变量地址进来 , 用于保存新线程的tid(线程ID)
  • const pthread_attr_t *attr:线程属性设置 , 如使用默认属性 , 则传NULL
  • void *(*start_routine) (void *):函数指针 , 指向新线程应该加载执行的函数模块
  • void *arg:指定线程将要加载调用的那个函数的参数
返回值
  • 成功返回0 , 失败返回错误号 。 可以先用strerror()把错误码转换成错误信息再打印
获取调用线程号#include pthread_t pthread_self(void);返回值
  • 返回当前线程号
线程退出#include 【Linux服务器开发——详解线程】void pthread_exit(void *retval);参数
  • rval_ptr是线程结束时的返回值 , 可由其他函数获取 , 如pthread_join() 。
注意
  • 如果进程中任何一个线程调用exit()或_exit() , 那么整个进程都会终止 。
  • 线程的正常退出方式有:线程从线程函数中返回、线程可以被另一个线程终止以及线程自己调用pthread_exit()函数
等待线程回收函数说明:阻塞调用函数 , 直到指定的线程终止 , 若线程不回收就类型僵进程 , 占用资源
#include int pthread_join(pthread_t thread, void **retval);参数
  • pthread_t thread:回收线程的tid
  • void **retval:接收退出线程传递出的返回值 , 不接收传NULL
返回值
  • 成功返回0 , 失败返回错误号
取消进程函数说明:取消线程 , 该函数在其他线程中调用 , 用来强行杀死指定的线程 , 也需要pthread_join回收
#include int pthread_cancel(pthread_t thread);参数
  • 线程ID号
线程清除通过调用pthread_detach()函数 , 结束线程 , 资源由系统自动释放 。 不用调用pthread_join
#include int pthread_detach(pthread_t tid);参数
  • pthread_t tid:分离线程tid
返回值