011 Linux_线程概念与创建

前言

本文将会向你介绍线程的概念,以及线程是怎么被创建的

线程概念

一、进程是承担系统资源的基本实体,线程是cpu调度的基本单位

首先,地址空间在逻辑上相当于进程的资源窗口, 每个进程都有这样一个资源窗口。通过地址空间+页表获取自身的代码和数据
在这里插入图片描述

那么有没有可能创建一个“进程”只需要创建一个pcb进程控制块即可?(以前创建进程,需要创建地址空间,页表,建立映射关系等等)

只需要创建一个pcb和父进程指向同一个地址空间的起始位置 注定了每一个“进程”看到的是同一个资源窗口(包括主进程,再创建几个进程,每个pcb都指向同一个地址空间,这意味着每个进程都能看到同一份“资源”),把代码拆成几个部分,把该共享的共享,不该共享的每个“进程”各一份,每个"进程"只会执行一部分代码

在这里插入图片描述
其实后续创建的每一个“进程”就是linux给出的线程的概念

每一个执行流占一份,每个执行流只需要占页表的一部分,就可以看到每一个区域不同的资源块
创建线程的量级明显比创建进程的要低, 创建进程要从0创建,pcb地址空间构建各种映射关系,页表,加载代码和数据,动态库也要加载,初始化各种代码和数据等等
创建线程只需要创建个pcb,并没有过多的资源申请,线程是参与资源分配的

LInux中线程的实现方案

操作系统只给线程是什么,特征是什么
具体一款os,无论底层怎么实现,只要符合给出的线程概念,就是线程,在教材里只给出线程的特征,但并不给出怎么实现线程,需要各个平台去实现符合概念的线程
(就好比不管你读的哪个大学,读的清华,还是北大,都是大学生)

综上所述:

1.线程创建更简单,
2.线程在进程的地址空间中运行(在进程内部中运行) 主进程创建时,申请地址空间,页表等等资源等到后续再创建线程时,就只需要创建一个pcb即可指向同一个地址空间,分配其中的资源,因此线程在进程的地址空间中运行

想必第一点你已经理解了,线程的创建更加地简单
那么第二点该如何理解呢?
从前的进程:内部只有一个执行流(红色框内的表示进程)
在这里插入图片描述

现在的进程(进程=内核数据结构+代码和数据):内部有多个执行流(整个红色框内表示一个进程)
其中第一个线程表示的是主线程
因此回到开头,进程(整个红色框所包含的)是承担系统资源的基本实体,而线程(一个个task_struct)是cpu调度的基本单位
在这里插入图片描述
往后cpu看到一个pcb就执行该pcb的方法,方法只需要能在地址空间上被分配资源,cpu就执行进程代码的一部分,访问进程数据的一部分
因此真实在cpu上真实跑的执行流(轻量级进程—线程)就比传统进程的量级要低一些

线程的创建

功能:创建一个新的线程
原型 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (start_routine)(void), void *arg);
参数:
thread:返回线程ID attr:设置线程的属性
attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数 返回值:成功返回0;失败返回错误码

绝大多数函数的名字以“pthread_”打头的函数
要使用这些函数库,要通过引入头文件<pthread.h> 链接这些线程函数库时要使用编译器命令的“-lpthread”选项

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
int gcnt = 100;
//新线程
void *ThreadRoutine(void *arg)
{
    const char *threadname = (const char *)arg;
    while(true)
    {
        std::cout<<"I am a new thread:" << threadname << ",pid: "<< getpid() << "gcnt:" << gcnt << "," << &gcnt << std::endl;
        gcnt--;
        sleep(1);
    }
}
int main()
{
    pthread_t tid1;  //实际上pthread_t就是无符号长整形
    //创建线程1
    pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");
    sleep(2);

    //主线程
    while(true)
    {
        std::cout << "I am main thread" << std::endl;
        sleep(1);
    }
    return 0;
}

通过

ps -aL 命令来查看线程id

在这里插入图片描述
现象:打印的pid是一样的,说明两个线程是属于同一个进程里的线程,因此获取的pid相同(理解:可以看看前文讲的现在的进程是怎样的)
LWP是用来区分线程的,全名是LIGHT WEIGHT PROCESSES轻量级进程(也就是线程)
在第一行中PID与LWP相同的就是主线程

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
int gcnt = 100;
void *ThreadRoutine(void *arg)
{
    const char *threadname = (const char *)arg;
    while(true)
    {
        std::cout<<"I am a new thread:" << threadname << ",pid: "<< getpid() << "gcnt:" << gcnt << "," << &gcnt << std::endl;
        gcnt--;
        sleep(1);
    }
}
int main()
{
    pthread_t tid1;  //实际上pthread_t就是无符号长整形
    //创建线程1
    pthread_create(&tid1, NULL, ThreadRoutine, (void*)"thread 1");
    sleep(2);
    pthread_t tid2;
    //创建线程2
    pthread_create(&tid2, NULL, ThreadRoutine, (void*)"thread 2");
    sleep(2);
    pthread_t tid3;
    //创建线程3
    pthread_create(&tid3, NULL, ThreadRoutine, (void*)"thread 3");
    sleep(2);
    //主线程
    while(true)
    {
        std::cout << "I am main thread" << std::endl;
        sleep(1);
    }
    return 0;
}

现象:所有线程共享同一份地址空间(共享同一份资源,观察:每个线程上对gcnt变量的修改在全局上有效)
在这里插入图片描述

小结

今日的分享就到这里啦,如果本文存在疏漏或错误的地方,还请您能够指出!

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

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

相关文章

《热辣滚烫》:用坚持不懈开启逆境中的职场出路

"你只活一次&#xff0c;所以被嘲笑也没有关系&#xff0c;想哭也没有关系&#xff0c;失败更没有关系。" “人生就像一场拳击赛&#xff0c;你站不起来&#xff0c;就永远不知道自己有多强” “命运只负责洗牌&#xff0c;出牌的永远是自己。” 在今年的贺岁档电影市…

MySQL的21个SQL经验

1. 写完SQL先explain查看执行计划(SQL性能优化) 日常开发写SQL的时候,尽量养成这个好习惯呀:写完SQL后,用explain分析一下,尤其注意走不走索引。 explain select userid,name,age from user where userid =10086 or age =18;2、操作delete或者update语句,加个limit(S…

C++之stack

1、stack简介 stack是实现的一个先进后出&#xff0c;后进先出的容器。它只有一个出口&#xff0c;只能操作最顶端元素。 2、stack库函数 &#xff08;1&#xff09;push() //向栈压入一个元素 &#xff08;2&#xff09;pop() //移除栈顶元素 &#xff08;3…

IO多路转接

1.select 初识select 系统提供 select 函数来实现多路复用输入 / 输出模型 . select 系统调用是用来让我们的程序监视多个文件描述符的状态变化的 ; 程序会停在 select 这里等待&#xff0c;直到被监视的文件描述符有一个或多个发生了状态改变 ; select函数模型 select的函…

LaTeX-设置表格大小

文章目录 LaTeX-设置表格大小1.创建表格2.设置表格的宽度2.1控制表格每一列的宽度2.2控制整个表格的宽度 3.设置表格的外观4.LaTeX绘制三线表 LaTeX-设置表格大小 本文介绍了LaTeX如何设置表格的大小、改变表格的外观以及如何绘制三线表。 1.创建表格 在LaTeX中创建表很耗时…

RocketMQ学习笔记一

课程来源&#xff1a;002-MQ简介_哔哩哔哩_bilibili &#xff08;尚硅谷老雷&#xff0c;时长19h&#xff09; 第1章 RocketMQ概述 1. MQ是什么&#xff1f; 2. MQ用途有哪些&#xff1f; 限流削峰&#xff1b;异步解耦&#xff1b;数据收集。 3. 常见MQ产品有哪些&对比…

10-Java装饰器模式 ( Decorator Pattern )

Java装饰器模式 摘要实现范例 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其结构 装饰器模式创建了一个装饰类&#xff0c;用来包装原有的类&#xff0c;并在保持类方法签名完整性的前提下&#xff0c;提供…

测试/测试开发八股——找大厂测试实习基础篇

第一部分:基础概念 1. 软件测试是什么? 在规定的条件下对一个产品或者程序进行操作,以发现程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程。 软件测试工程师的任务 2. 软件测试工程师的任务 软件测试工程师主要工作是检查软件是否有bug、是否具有稳定…

【深度学习笔记】计算机视觉——图像增广

图像增广 sec_alexnet提到过大型数据集是成功应用深度神经网络的先决条件。 图像增广在对训练图像进行一系列的随机变化之后&#xff0c;生成相似但不同的训练样本&#xff0c;从而扩大了训练集的规模。 此外&#xff0c;应用图像增广的原因是&#xff0c;随机改变训练样本可以…

Spring对IoC的实现

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

GO-并发

1. 并发 有人把Go语言比作 21 世纪的C语言&#xff0c;第一是因为Go语言设计简单&#xff0c;第二则是因为 21 世纪最重要的就是并发程序设计&#xff0c;而 Go 从语言层面就支持并发。同时实现了自动垃圾回收机制。 先来了解一些概念&#xff1a; 进程/线程 进程是程序在操…

Bootstrap的使用

目录 js的引入&#xff1a; 1.行内式 2.嵌入式 3.外链式 Bootstrap:的引入 注意事项&#xff1a; 条件注释语句&#xff1a; 栅格系统&#xff1a; 列嵌套&#xff1a; 列偏移&#xff1a; 列排序&#xff1a; 响应式工具&#xff1a; Bootstrap的字体图标的使用&a…

探讨苹果 Vision Pro 的 AI 数字人形象问题

Personas 的设计模糊性&#xff1a; 部分人认为这种模糊设计可能是出于安全考虑&#x1f6e1;️。安全角度&#xff1a;Personas 代表着你的 AI 数字形象&#xff0c;在创建时&#xff0c;它相当于你的 AVP&#xff08;生物识别扫描器的存在增加了冒充的难度&#xff09;。如果…

mysql服务治理

一、性能监控指标和解决方案 1.QPS 一台 MySQL 数据库&#xff0c;大致处理能力的极限是&#xff0c;每秒一万条左右的简单 SQL&#xff0c;这里的“简单 SQL”&#xff0c;指的是类似于主键查询这种不需要遍历很多条记录的 SQL。 根据服务器的配置高低&#xff0c;可能低端…

Java ZooKeeper-RocketMQ 面试题

Java ZooKeeper-RocketMQ 面试题 前言1、谈谈你对ZooKeeper的理解 &#xff1f;2、Zookeeper的工作原理&#xff08;Zab协议&#xff09;3、谈谈你对分布式锁的理解&#xff0c;以及分布式锁的实现&#xff1f;4、 zookeeper 是如何保证事务的顺序一致性的&#xff1f;5、 zook…

使用lnmp环境部署laravel框架需要注意的点

1&#xff0c;上传项目文件后&#xff0c;需要chmod -R 777 storage授予文件权限&#xff0c;不然会报错file_put_contents(/): failed to open stream: Permission denied。 如果后面还是报错没有权限的话&#xff0c;就执行ps -ef |grep php查询php运行用户。然后执行chown …

STM32-ADC一步到位学习手册

1.按部就班陈述概念 ADC 是 Analog-to-Digital Converter 的缩写&#xff0c;指的是模拟/数字转换器。它将连续变量的模拟信号转换为离散的数字信号。在 STM32 中&#xff0c;ADC 具有高达 12 位的转换精度&#xff0c;有多达 18 个测量通道&#xff0c;其中 16 个为外部通道&…

小朋友来自多少小区 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 幼儿园组织活动&#xff0c;老师布置了一个任务&#xff1a; 每个小朋友去了解与自己同一个小区的小朋友还有几个。 我们将这些数量汇总到数组 garden 中。 请…

gofly框架接口入参验证使用介绍

接口传入的参数做相关性质验证是开发中较为常用&#xff0c;gofly框架内置校验工具&#xff0c;提供开发效率&#xff0c;开发接口简单调用即可实现验证&#xff0c;下面介绍gofly框架数据验证设计思路及使用方法。 gofly框架提供了功能强大、使用便捷、灵活易扩展的数据/表单…

jupyter调用envs环境——jupyter内核配置虚拟环境

1.jupyter无法使用envs环境 pycharm的终端打开jupyter notebook&#xff1a; 在kernel下找不到上面的Pytorch_GPU环境&#xff1a; 2.解决方法 在对应的envs环境中安装ipykernel&#xff1a; 将该环境写入jupyter&#xff1a; python -m ipykernel install --user --name Py…