【Linux】线程Pthread的概念 | NPTL线程库函数

创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!!
主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步!
🔥Linux系列专栏:Linux基础 🔥

给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ

在这里插入图片描述


一、线程的概念

线程是操作系统能够进行调度和执行的最小单位。它是进程内执行的一个独立单元,与同一进程中的其他线程共享进程的地址空间和系统资源。

线程能减少程序在并发执行时所付出的时空开销,使操作系统具有更好的并发性。

二、线程和进程

一般情况下进程包含线程,线程比进程更轻量(体积更小,开销更小)

进程是最小的分配资源单位,线程是最小的调度单位

线程不分配内存,线程创建于进程中,与进程共享资源,访问进程的内存,完成特定任务

类 Unix 系统中,早期是没有“线程”概念的,80 年代才引入,借助进程机制实现出了线程的概念。因此在这类系统中,进程和线程关系密切
轻量级进程(light-weight process)也有 PCB,创建线程使用的底层函数和进程一样,都是 clone
从内核里看进程和线程是一样的,都有各自不同的 PCB,但是 PCB 中指向内存资源的三级页表是相同的
进程可以退化成线程
线程可看做寄存器和栈的集合,线程可以占用时间片使用cpu,可以通过保存和恢复处理器现场避免寄存器冲突,所以线程是一个合格的调度单位。
在 linux下,线程最是小的执行单位;进程是最小的分配资源单位
多线程可以共享资源,减少内存开销

进程退化

如果进程中创建了新的线程,那么进程原本的执行单元成为主控线程,新创建的成为普通线程,便于区分和理解。

线程分为内核级线程KLT和用户级线程ULT

cpu会给每个内核级线程分配内核对象,与进程一样获取cpu

  • 优点:内核级线程可以得到更多的系统资源,缩短任务完成时间
  • 缺点:所有的线程资源分配、访问和上下文切换都需要系统干预,开销较大

系统无法识别用户级线程,无法将资源分发给普通线程,只会给用户级进程

普通线程虽然无法直接被系统分发资源,但是可以使用cpu(可以主线程sleep(0)放弃时间片,给同进程下的普通进程时间片)
优点:用户级线程的创建、撤销和切换与OS内核无关,由用户空间中的线程库完成,系统调度开销小

多个线程在进程中共享资源有哪些?

  • 1.全局变量
  • 2.文件描述符
  • 3.PCB
  • 4.堆空间
  • 5.信号处理行为

非共享资源:

  • 1.线程栈
  • 2.TCB
  • 3.优先级指针·
  • 4.信号屏蔽字
  • 5.errno全局变量

二、线程函数

创建线程

int pthread_create(pthread_t *tid, const pthread_attr_t *attr, void *(*start_rountn)(void *), void *arg);

返回值:

  • 创建成功 返回0
  • 创建失败 返回errno

参数:

  • tid:传出参数,表示为创建的子线程id
  • attr:线程属性,传 NULL代表默认属性
  • start_rountn:子线程回调函数,函数指针,为线程工作地址。ptherad_create函数返回时,该函数会被自动调用
  • arg:start_rountn函数参数,系统创建线程后调用start_rountn后把arg传入twk函数中
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

void* job(void* arg)
{
   
	//子线程
	while(1)
	{
   
		printf("child thread running...\n");
		sleep(1);
	}
}

int main()
{
   
	//主线程
	pthread_t tid;
	int err;
	
	if( (err = pthread_create(&tid,NULL,job,NULL) ) > 0)
	{
   
		printf("thread_create failed:%s\n",strerror(err));
		exit(0);
	}
	while(1)
	{
   
		printf("parent thread running...\n");		
		sleep(1);
	}
	return 0;
}

在这里插入图片描述

获取线程id

pthread_t pthread_self();

返回值:

  • 本线程id

主线程创建成功后传出tid,与普通线程内部获取的tid 值相等,但是不等价

线程内部id即pthread_self()可以保证线程当前有效性,但是其他线程中的tid即创建线程时传出的tid无法保证是否存活

线程回收

如果不回收将会引发僵线程(TCB)残留

void pthread_join(pthread_t tid,void** retval);

阻塞函数,线程未退出会等待,退出后立即回收
返回值:

  • 创建成功返回0
  • 创建失败返回errno

函数参数:

  • tid:待回收的线程id
  • reval:传出参数,为线程函数的返回值

线程退出

pthread_exit((void*)retval)

返回值:

  • 创建成功返回0
  • 创建失败返回errno

函数参数:

  • reval:传出参数,为线程函数的返回值

线程取消

pthread_cancel(pthread_t tid);

返回值:

  • 创建成功返回0
  • 创建失败返回errno

函数参数:

  • tid:待取消的线程id

可以将目标线程杀死,不能保证杀掉。只有目标线程内有系统调用如printf、sleep,才能杀掉
可以使用pthread_testcancel()函数 触发一次系统调用,不进行其他操作。

被 cancel 杀死的线程再用 pthread_join 回收,返回值为-1

设置线程分离

int pthread_detach(pthread_t tid);

返回值:

  • 成功:0
  • 失败:errno

得到线程的返回值,使用回收态。系统自动回收使用分离态


在这里插入图片描述

大家的点赞、收藏、关注将是我更新的最大动力! 欢迎留言或私信建议或问题。
大家的支持和反馈对我来说意义重大,我会继续不断努力提供有价值的内容!如果本文哪里有错误的地方还请大家多多指出(●'◡'●)

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-02-07 18:54:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-02-07 18:54:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-02-07 18:54:03       82 阅读
  4. Python语言-面向对象

    2024-02-07 18:54:03       91 阅读

热门阅读

  1. Vue+Koa项目完整上线流程中遇到的问题

    2024-02-07 18:54:03       43 阅读
  2. 【0258】pg内核支持的所有 inval messages 类型

    2024-02-07 18:54:03       54 阅读
  3. 低代码平台痛点

    2024-02-07 18:54:03       51 阅读
  4. Windows下配置多个账号的git ssh

    2024-02-07 18:54:03       50 阅读
  5. VoIP之主备注册服务器机制

    2024-02-07 18:54:03       54 阅读
  6. 新环境常用国内镜像合集

    2024-02-07 18:54:03       50 阅读
  7. vue的事件修饰符和常用的按键别名

    2024-02-07 18:54:03       42 阅读
  8. LeetCode 丑数

    2024-02-07 18:54:03       55 阅读
  9. C++俄罗斯方块 -- 菜单展示和选择 -- 方法

    2024-02-07 18:54:03       54 阅读
  10. C#面:ASP.NET中常见的内置对象

    2024-02-07 18:54:03       48 阅读