Linux--线程

一:线程

1.线程的相关概念:

  • 线程是比进程粒度更细的执行流
    理解:
    (1) 每一个线程的数据代码都是目标进程的子集
    (2)线程于线程数据和代码大部分都共享
    (3)线程的创建和释放成本非常低
    (4)线程的调度成本很低

  • 线程是在进程内部运行的执行流

  • Linux下没有真正的线程,是用进程模拟线程(操作系统没有专门为线程创建对应的结构体),Linux下的线程叫轻量级进程。
  • 线程在进程的地址空间运行
  • 线程是cpu调度的基本单位
  • 进程是承担系统分配资源的基本单位

2.线程私有的和多个线程共享的数据

  • 每个线程私有的数据:线程ID、一组寄存器(保存自己独立的上下文信息)、栈(私有栈)、信号屏蔽字、调度优先级。
  • 进程内部多个线程共享的数据:文件描述符、每种信号的处理方式、用户ID和组ID

3.线程的优点

  • 创建一个新县城的代价要比创建一个进程小很多。
  • 与进程的切换相比,线程之间的切换需要操作系统做的事情少很多
  • 线程占用的资源要比进程少很多。
  • 能充分利用多处理器的可并行数量

4.线程的缺点

  • 性能损失
  • 健壮性降低
  • 缺乏访问控制
  • 编程难度提高

二:线程控制:

1.POSIX线程库(用户级线程库):

  • 因为Linux下是没有真正的线程,所以系统是没有对应的接口。
  • 就有人开发了POSIX线程库,使用这些库函数,要引用头文件pthread.h
  • 链接这写线程函数库时要使用编译器命令的“-lpthread”选项(链接库)

2.创建线程:

  • int pthread_create(pthread_t thread, const pthread_attr_t *attr, void (start_routine) (void ), void *arg); //第一个参数为线程ID(库提供的ID),第二个参数设置线程的属性(NULL表示默认属性),第三个参数是函数地址,线程启动后要执行的函数,最后一个参数是传给线程启动函数的参数。返回0表成功,出错返回错误码
    这里写图片描述

3.线程等待(主线程等待):

  • int pthread_join(pthread_t thread, void **retval);//阻塞式等待,第一个参数为所等的线程ID,第二个参数为输出型参数,获得所等待线程的退出信息。
  • 注:已经退出的线程,其空间没有被释放仍然在进程的地址空间内,创建新的线程不会复用刚才退出线程的地址空间,所以需要等待。线程退出不可能是异常退出,因为异常退出的话,整个进程就挂了,没机会等待了。
    这里写图片描述

4.线程终止:

  • 三种终止情况
    (1)代码跑完,结果正确
    (2)代码跑完,结果不正确
    (3)异常退出。 在运行期间,只要有一个线程出错异常退出,全部线程(进程)就会挂掉。
  • 只终止某个线程而不是整个进程的方法:
    (1)线程调用exit就是进程调用exit,就是进程退出。
    (2)主线程调用return是指进程退出,而线程调用指线程退出
    (3)pthread_exit(void *retval);是线程退出,主线程退出就是进程退出,不能调用pthread_exit.
    (4)pthread_cancel(pthread_t thread);//取消某个线程,也可以取消自己。
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

5.线程ID及地址空间布局

  • 多线程的进程,又被称为线程组,线程组内的每一个线程在内核之中都存在一个进程描述符(task_struct)与之对应。进程描述符结构体中的pid,表面上看对应的是进程ID,其实不然,它对应的是线程ID;进程描述中的tgid,含义是Thread Group ID, 该值对应的是用户层面的进程ID。
    这里写图片描述
  • 这里的PID就是getpid的返回值,LWP就是gettid()的返回值,是在系统级别内有效。
    pthread_t pthread_self(void); //这里返回的线程ID,属于NPTL线程库的范畴,只在当前库下有效。实质上就是动态库对应线程对应的起始地址。

注: Linux提供了gettid系统调用来返回其线程ID,可是glibc并没有将系统调用封装起来,在开放接口来共程序员使用,如果想要获取线程ID,可采用如下方法:
这里写图片描述

  • 进程地址空间布局:
    这里写图片描述

6.线程分离:

  • 默认情况下,新创建的线程是joinable(可结合的),线程退出后,需要对其进行等待。如果不关心线程的返回值,join就是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
  • int pthread_detach(pthread_t thread);//线程组内的其他线程对目标线程进行分离,也可以是线程自己分离。

猜你喜欢

转载自blog.csdn.net/virgofarm/article/details/80635796