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变量的修改在全局上有效)
在这里插入图片描述

小结

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

  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fan_558

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值