【linux线程(一)】什么是线程?怎样操作线程?

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:Linux从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学更多操作系统知识
  🔝🔝


在这里插入图片描述

Linux线程

  • 1. 前言
  • 2. 什么是线程?
  • 3. 线程和进程的区别和联系
  • 4. Linux下如何操作线程?
  • 5. pthread线程库讲解
  • 6. 线程和前面知识的汇总
  • 7. 总结以及拓展

1. 前言

可能大家对多线程这三个字早有耳闻,
那么到底什么是线程?为什么要有它?
它和进程之间有什么联系?

本章重点:

本篇文章着重讲解线程的基本概率,
以及进程和线程的对比,最后会讲解
在Linux下如何创建,控制,终止,等待线程


2. 什么是线程?

程序中的一个执行路线就叫做线程

一个进程至少要有一个执行线程,单个进程本身就是一个执行流,所以单个进程某种意义上也是一个线程(是主线程).线程在进程内部运行,本质是在进程地址空间内运行.在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化

在Linux系统下,线程是轻量化的进程,我们知道进程有PCB结构和程序地址空间,那么线程的话只有PCB,它的地址空间是和主线程共享的,如下图:

在这里插入图片描述

综上所述,线程就是一个没有独立的地址空间的PCB结构,线程的资源是从最开始的主线程,也就是进程来的.而站在CPU的视角,CPU调度的是PCB结构,CPU只认PCB,它并不关心此PCB是进程的还是线程的,所以线程被称为系统调度的基本单位.而在Linux操作系统下,线程就是轻量化的进程


3. 线程和进程的区别和联系

通过上面对线程的描述,我们可以窥探到:

  1. 线程是担任系统调度的基本实体
  2. 进程是担任系统资源分配的基本实体

虽然线程共享进程数据,但也拥有自己的数据:

  • 线程ID
  • 栈区资源
  • 信号屏蔽字
  • 调度优先级

在这里插入图片描述

使用指令: ps -al查看线程ID

在这里插入图片描述

主线程的PID和LWP相同,CPU调度时是在看LWP,而不是PID,线程的PID和主线程相同,自己独有LWP

在这里插入图片描述


4. Linux下如何操作线程?

在这里插入图片描述

由于pthred是第三方库
所以编译时要加上-lpthread的字段

  1. 如何创建线程

在这里插入图片描述

第一个参数需要传入一个pthread_t类型的变量,这个变量我们需要先定义.所谓的pthread_t,实际上本质就是unsigned long int类型,第二个参数我们一般设置为空.第三个参数要传入线程启动后要执行的函数的地址,这个函数的返回值和参数都是void*,最后一个参数是传入给函数形参的,要强转为void*

一般的编码格式:

void *route(void *arg) {
	while(1) {
		printf("I'am a thread \n");
		sleep(1);
	}
}
int main()
{
	pthread_t tid;
	int ret;
	if ( (ret=pthread_create(&tid, NULL, rout, NULL)) != 0 ) {
		fprintf(stderr, "pthread_create : %s\n", strerror(ret));
		exit(-1); //如果创建线程失败会走进此语句
	}
	int i;
	for(; ; ) {
		printf("I'am main thread\n");
		sleep(1);
	}
	return 0;
}
  1. 如何终止线程

在这里插入图片描述

一般使用return返回的来终止线程

  1. 如何进行线程等待

在这里插入图片描述

假如不进行线程等待,可能会出现类似于僵尸进程的问题

一般编码格式:

void *thread_run( void * arg )
{
	pthread_detach(pthread_self());
	printf("%s\n", (char*)arg);
	return NULL;
}
int main( void )
{
	pthread_t tid;
	if ( pthread_create(&tid, NULL, thread_run, "thread1 run...") != 0 ) {
		printf("create thread error\n");
		return 1;
	}
	int ret = 0;
	sleep(1);//很重要,要让线程先分离,再等待
	if ( pthread_join(tid, NULL ) == 0 ) {
		printf("pthread wait success\n");
		ret = 0;
	} else {
		printf("pthread wait failed\n");
		ret = 1;
	}
	return ret;
}
  1. 如何进行线程分离

假如创建一个线程后,不想关心它的返回值,此时使用join等待实际上是一种负担,所以使用线程分离后,可以把创建的线程和主线程分离,这样就不会影响到主线程

在这里插入图片描述

pthread_self()函数可以返回当前线程的线程ID,所以假设我们想要当前线程与主线程脱离关系,可以这样写: pthread_detach(pthread_self());

一般编码格式:

void *thread_run( void * arg )
{
	pthread_detach(pthread_self());
	printf("%s\n", (char*)arg);
	return NULL;
}
int main( void )
{
	pthread_t tid;
	if ( pthread_create(&tid, NULL, thread_run, "thread1 run...") != 0 ) {
		printf("create thread error\n");
		return 1;
	}
	int ret = 0;
	sleep(1);//很重要,要让线程先分离,再等待
	if ( pthread_join(tid, NULL ) == 0 ) {
		printf("pthread wait success\n");
		ret = 0;
	} else {
		printf("pthread wait failed\n");
		ret = 1;
	}
	return ret;
}

5. pthread线程库讲解

首先,pthread_create的返回值是线程ID.
那么线程ID的本质是什么呢?

答案是,线程ID的本质是一个地址,pthread库是一个动态库,是第三方库,这个库会被映射到进程的地址空间的共享区中,而线程ID所指的地址则是pthread这个库层面上,线程集合的起始地址

在这里插入图片描述

再回忆一下刚才的内容,线程有自己的栈区,也就是说线程要维护自己的栈区,那么可以联想一下,谁帮线程维护这个栈区呢?答案是pthread库维护的栈区,也就是说其实线程的栈区也是被映射到共享区的,由pthread第三方库维护


6. 线程和前面知识的汇总

这里有三个问题要思考一下:

  1. 线程异常退出后,主线程也会退出吗?
  2. 线程可以用fork创建子进程吗?
  3. 线程可以进行进程程序替换吗?
  • 第一个问题

一个进程(主线程)可以拥有多个线程,这多个线程只要其中一个线程发生错误,导致此线程退出,那么所有的线程包括主线程都会退出.所以在编写线程函数时,一定要多加小心

  • 第二个问题

线程可以通过函数fork来创建子进程,并且在实际运用中是有被使用到的实例

  • 第三个问题

线程不能进行进程程序替换,因为线程是共用主线程的资源,一旦一个线程进行进程程序替换后,所有的线程包括主线程的代码都会被替换为别的程序,这显然是不正确的


7. 总结以及拓展

最后,创建线程有优点也有缺点,在实际
编写代码中大家根据自己的需求来定

在这里插入图片描述
在这里插入图片描述

在某些多线程的场景下,执行一段代码可能会出现不一样的结果,这就是线程的安全问题,关于线程的安全问题以及线程互斥和线程同步的概率会在下一篇文章讲解


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/450165.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阻塞队列学习

1、什么是阻塞队列? 顾名思义,就是支持阻塞的队列,相比于其他的队列,阻塞队列支持以下特性: 队列为空的时候,获取元素的线程会等待队列变为非空。队列为满的时候,存储元素的线程会等待队列可以…

认证授权与JWT

认证授权与JWT 1、认证授权概念介绍1.1 什么是认证1.2 什么是授权 2、权限数据模型3、RBAC权限模型3.1 介绍3.2 基于角色访问控制3.3 基于资源访问控制 4、常见认证方式4.1 Cookie-Session4.2 jwt令牌无状态认证 5 常见技术实现6.Jwt介绍6.1 JWT简介6.2.Jwt组成 7、JWT使用7.1 …

JFMQL100TAI900/JFMQL100T900全国产化 ARM 核心板+扩展板/全国产开发板

TEC100TAI-KIT 是一款基于青龙100TAI 的全国产智能异构计算平台开发套件,该套件包含 1个 100TAI 核心板和 1 个 PCIE 规格的扩展底板。该 套 件 的 核 心 板 集 成 了 100TAI 的 最 小 系 统 , 包 含 一 颗JFMQL100TAI900 片上系统芯片,该单颗…

5、Async await(等待异步)、函数的防抖和节流、模块化

一、Async await(等待异步) Async去声明函数,返回一个promise对象,await在声明的函数里面使用 function fn_1() {return fn_1 } function fn_2() {return new Promise((reslove) > {setTimeout(() > {//因为定时器是异步的 num 10return reslov…

使用gnvm下载nodejs和npm

目录 前言 一、下载gnvm 二、利用gnvm下载nodejs 三、下载对应版本的npm 四、gnvm常用的命令 总结 前言 由于之前下载的版本过低,需要升级版本。但在使用gnvm升级node版本时遇到了一系列的问题,索性就把nodejs全部删除,重新用gnvm在下…

【保姆级教程】JDK安装与环境变量配置

文章目录 第一步:下载JDK(以1.8为例)第二步:安装第三步:找到默认安装目录第四步:配置环境变量(win10为例) 大家可能会遇到的疑问:一个电脑可以安装多个版本的jdk没有问题…

抽样算法——【数据科学与工程算法基础】

一、前言 这是课程的第二章节——抽样算法,主要分为三类。 详情可参考: 数据科学的算法基础——学习记录跳转中心 二、正篇 1.系统抽样 课本只介绍了最简单的——等距抽样。 直线等距抽样(Nn*k):即总体个数可以被抽…

swiftUI 中如何忽略safeArea

swiftUI 中如何忽略safeArea 不管是UIKit和swiftUI为了能适配更多设备,所以出来了一个safeArea的设定。那如何把我们的控件放到safeArea里面呢 答案就是ignoresSafeArea ignoresSafeArea 通过把Text空间放到一个VStack下然后给VStack设置宽高无限大,就…

如何选择合适的IP代理,如何为网络爬虫设置代理

目录 前言 1. 代理类型的选择 2. 代理速度 3. 代理稳定性 4. 代理的匿名性 5. 代理的地理位置 总结 前言 在进行网络爬虫任务时,为了避免被目标网站封禁IP或限制访问频率,我们通常会使用代理来隐藏真实的IP地址。选择合适的IP代理对于爬虫的成功…

1. DDPM模型概述

1. DDPM模型概述 扩散模型(DM,Diffusion Model)是一类生成模型,常见的生成模型还有GAN和VAE。扩散模型分为前向阶段和逆向阶段,在前向阶段中逐步向数据中添加噪声,直至数据变成完全的高斯噪声,…

Redis高可用之哨兵模式和集群模式

Redis高可用 Redis哨兵高可用 概述 sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。 哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点 不会每次都通过sentinel代理访问redis的主…

网络地址转换协议NAT

网络地址转换协议NAT NAT的定义 NAT(Network Address Translation,网络地址转换)是1994年提出的。当在专用网内部的一些主机本来已经分配到了本地IP地址(即仅在本专用网内使用的专用地址),但现在又想和因…

YOLOv8改进 | 注意力机制 | 添加YOLO-Face提出的SEAM注意力机制优化物体遮挡检测(附代码 + 修改教程)

一、本文介绍 本文给大家带来的改进机制是由YOLO-Face提出能够改善物体遮挡检测的注意力机制SEAM,SEAM(Spatially Enhanced Attention Module)注意力网络模块旨在补偿被遮挡面部的响应损失,通过增强未遮挡面部的响应来实现这一目标,其希望通过学习遮挡面和未遮挡面之间的…

Word转PDF保持图片原有清晰度

目录 1、需要的软件 2、配置Acrobat PDFMaker 3、配置Acrobat Distiller 4、更改Acrobat PDFMaker中的首选项 5、将word转换成pdf 1、需要的软件 利用Adobe Acrobat DC工具。 打开word,选择Acrobat的插件,选择首选项。 如果没有出现Acrobat插件也…

Java学习记录(十七)IO流(三)

转换流(在字节流中想使用字符流的方法时使用) 转换流是字节流和字符流之间的桥梁,转换流本身其实就是字符流所以可以使用字符流里的相关方法,通过InputStreamReader字符转换输入流能将字节流转化为字符流输入到内存中&#xff0c…

基于java的公寓报修管理系统设计与实现(程序+文档+数据库)

** 🍅点赞收藏关注 → 私信领取本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目,希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅** 一、研究背景…

portraiture2024汉化版PS人像处理的磨皮美化插件

Portraiture插件是一款广泛应用于人像处理的磨皮美化插件,尤其在Photoshop和Lightroom等图像编辑软件中备受欢迎。这款插件能够帮助用户快速实现智能磨皮效果,使皮肤看起来更加平滑细腻,同时保留自然纹理和其他重要细节。Portraiture是一款适…

STM32利用标准库编写同时输出4路PWM信号的程序(Proteus)仿真

先看看结果: 这个是根据上午发的文章的基础上更改的,很简单,只是用了一个定时器,初始化了4个比较器而已,就可以单独的控制每一路PWM的占空比了,好了,把源文件展示一下,完事去接孩子放…

NCDA大赛中哪些HTML5设计作品展现出色?

与传统的HTML网页设计相比,HTML5网页设计主要是对网页内容的加强。HTML5已成为目前最流行的标记语言,拥有成熟的社区和广泛的浏览器支持,HTML5完整的功能和强大的扩展性使设计师和开发者能够点铁成金。HTML5可以一手控制更多可控元素&#xf…

eggjs+egg-mongoose操作mongodb数据库

使用的数据库是mongodb数据库,mongodb的数据库表创建就不一一介绍了,可自行查询资料如何创建数据库。 使用的数据库可视化工具是mongodb compass 使用的接口工具是postman 这里使用的egg项目脚手架模板是simple版本,详细创建项目流程可在egg…
最新文章