当前位置: 首页 > news >正文

Linux操作系统6- 线程1(线程基础,调用接口,线程优缺点)

上篇文章:Linux操作系统5- 补充知识(可重入函数,volatile关键字,SIGCHLD信号)-CSDN博客

本篇Gitee仓库:myLerningCode/l27 · 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com)

目录

一. Linux中的线程

1.1 线程的概念

1.2 OS管理线程的方式 

1.3 线程与进程

二. Linux中创建线程 ⭐

1.1 pthread_create系统调用

1.2 线程之间的资源共享

1.3 线程的私有资源⭐

三. 线程的优缺点 ⭐

3.1 线程的优点

3.2 线程的缺点 


一. Linux中的线程

1.1 线程的概念

        进程是OS调度的基本单位,进程 = PCB + 进程对应数据与代码。而线程是进程内的一个执行流。

        对于一个进程来说,进程是通过虚拟内存与页表的映射来访问物理内存的。所以一个进程的虚拟内存决定了这个进程所拥有的资源。

        在linux中,对于一个进程,如果定义多个PCB指向同一个虚拟内存。让后让这些PCB指向不同的物理内存区域,这些PCB就是线程。

        通过虚拟内存和页表的映射,我们对一个进程的资源进行了划分,这样一来,单个PCB的粒度就比整个进程粒度低。

 关系如下图:

 

其中,所有的PCB + 进程虚拟内存 + 页表 + 进程对应数据代码 = 一个进程

              单个PCB + 单个PCB占用的虚拟内存 + 页表 + 线程对应数据代码 = 一个线程

1.2 OS管理线程的方式 

        OS通过PCB来管理进程,同样所有的线程也需要被OS管理。

        如果想要管理线程,首先需要设计特定的内核数据结构来表示线程对象,即设计一个TCB(线程控制块)。

        Windows就是这样设计线程的。不过需要重新设计一个内核数据结构太麻烦了!

         线程和进程有很多资源是一样的,比如id状态,优先级,上下文,页表,虚拟内存,文件描述符...       

        因此Linux工程师使用直接复用进程的PCB,使用PCB来表示线程。而cpu只关心PCB不关心你是线程还是进程

        所以,线程在进程的地址空间中运行,拥有该进程一部分虚拟内存和资源。

1.3 线程与进程

        进程是承担系统分配资源的基本单位(PCB,虚拟内存,页表,代码和数据等资源)

        而线程是CPU调度的基本单位,在linux中称为轻量级进程\

总结:

1 在Linux中,没有严格的线程,只有轻量级进程,使用进程来模拟线程。

2 线程是cpu调度的基本单位,进程是系统分配资源的基本单位

        linux使用轻量级进程模拟线程的好处:降低维护成本,提高效率

        linux使用轻量级进程模型线程的坏处:用户只认线程,不认进程,所以linux需要为轻量级进程和线程之间提供线程库

二. Linux中创建线程 ⭐

1.1 pthread_create系统调用

        使用man手册查看如下:

可以看到,使用这个接口需要在编译的时候带上参数 -pthread

//头文件
#include <pthread.h>
//库名称
pthread

int pthread_creat(pthread_t *thread, const pthread_attr_t *attr, void* (*start_routine)(void*), void *arg)

//参数说明
thread    用于定义线程tid的地址,是输入输出型参数,调用后tid获取线程的id
attr      用于控制线程的属性,我们一般设置为0.表示默认属性
start_routine    线程运行函数的指针,即线程的执行流函数。调用后线程就执行该函数内部的代码
arg       线程函数start_routine的参数

测试代码:

makefile文件

test:test.cpp
	g++ -o $@ $^ -lpthread -std=c++11
.PHONY:clean
clean:
	rm -rf test

        在Linux中,使用线程必须要使用-l pthread用于链接原生线程库

test.cpp

#include <iostream>

#include <unistd.h>
#include <pthread.h>

void *start_routine(void *args)
{
    const char *name = static_cast<const char *>(args);
    while (true)
    {
        std::cout << "我是新线程,我的名字是" << name << "pid为:" << getpid() << std::endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid;                                                       // 定义线程tid
    pthread_create(&tid, nullptr, start_routine, (void *)"I am thread"); // 创建线程

    while (true)
    {
        std::cout << "我是主线程,我的pid为:" << getpid() << std::endl;
        sleep(1);
    }
    return 0;
}

测试结果如下:

        可以看到,主线程和新线程是并发执行的。

        并且使用 ps axj 命令查看只有一个test进程,二使用 ps -aL查看线程可以看到test进程内有两个线程,它们的pid是由于的而LWP是不一样的!

        CPU调度的时候,使用LWP来标识每一个线程。并且以进程中的主线程的LWP就是这个进程的pid。

1.2 线程之间的资源共享

        线程被创建后,会共享全局变量,函数等资源。

测试代码:

#include <iostream>

#include <unistd.h>
#include <pthread.h>

// 全局变量
std::string name = "线程基础";

// 全局函数
inline void f()
{
    std::cout << "调用全局函数" << " 读取全局变量:" << name << std::endl;
}

void *start_routine(void *args)
{
    const char *name = static_cast<const char *>(args);
    while (true)
    {
        std::cout << "我是新线程,我的名字是" << name << "pid为:" << getpid();
        f();
        sleep(1);
    }
}

int main()
{
    pthread_t tid;                                                       // 定义线程tid
    pthread_create(&tid, nullptr, start_routine, (void *)"I am thread"); // 创建线程

    while (true)
    {
        std::cout << "我是主线程,我的pid为:" << getpid();
        f();

        sleep(1);
    }
    return 0;
}

测试结果:

可以说明:线程能够调用全局函数,也可以读写全局变量。这说明两个线程之间如果想要进行通信是非常简单的。不像进程间通信需要通过OS创建资源,然后让两个进程看到同一份资源

 线程之间共享 虚拟内存的代码区,全局变量区,堆区,文件,信号处理

1.3 线程的私有资源⭐

        线程之间共享全局资源,每一个线程也有着自己独立的资源。

1 线程是CUP调度的基本单位,每一个线程有着自己的PCB,有自己独立的id,优先级

2 线程有着自己的上下文结构,这体现线程切换的动态属性。上下文是指线程切换的时候,cpu寄存器中的值,PCB的状态,PCB对应的堆栈结构。

3 每一个线程都有自己独立的栈结构。这个栈结构位于共享区

三. 线程的优缺点 ⭐

3.1 线程的优点

        1 线程的创建消耗比进程低很多

        2 线程切换与进程切换相比,需要OS工作更少,消耗低

为什么线程切换比进程切换开销小?

        1 进程切换需要切换进程的虚拟内存,页表,切换所有的PCB和上下文

        2 线程切换只需要切换一个PCB和线程自己的上下文

        3 线程切换不太用更新catch,进程切换需要更新所有的catch。catch是高速缓存,CPU通过catch与内存交流,一个稳定的进程,会缓存很多热点数据,这样一来,catch的命中率高,线程切换不怎么影响catch的命中率。

        如果切换了进程,需要全部更新catch,这个需要消耗较多的时间

3.2 线程的缺点 

        1 如果创建的线程过多,会造成一定的性能损失

        2 线程会导致代码的健壮性降低,因为一个线程异常退出了,会导致整个进程退出,线程崩溃了,整个进程会崩溃

        3 线程之间共享资源,需要考虑访问控制和同步互斥问题

相关文章:

  • 学习笔记:利用OpenAI实现阅卷智能体
  • AcWing 5438. 密接牛追踪2 区间覆盖问题的详细解释
  • 关闭Windows安全中心,解析与实操指南
  • Git基础之工作原理
  • Spark 3.0核心新特性解析与行业应用展望
  • Docker部署Ragflow(完美解决502 bad gateway)
  • 【RocketMQ 存储】- 异常退出恢复逻辑 recoverAbnormally
  • 机器学习数学基础:44.多元线性回归
  • VTK笔记- 3D Widget类 vtkSplineWidget 样条部件
  • Hadoop项目中的问题(1)——NetworkManager 和 network 服务冲突
  • mysql经典试题共34题
  • fastjson漏洞#不出网#原理#流量特征
  • CD10.【C++ Dev】类和对象(1)
  • 用户仿真任务调度管理平台数据库设计
  • 使用Qt调用HslCommunication(C++调用C#库)
  • 微服务拆分-远程调用
  • 电子学会—2024年12月青少年软件编程(图形化)级等级考试真题——猜年龄互动小游戏
  • Linux之Web控制台管理系统命令终端管理系统(保姆级)
  • 精选一百道题备赛蓝桥杯 —— 1.子串简写
  • 【AI】Deepseek本地部署探索,尝试联网搜索
  • 三星“七天机”质保期内屏幕漏液被要求自费维修,商家:系人为损坏
  • 习近平出席俄罗斯纪念苏联伟大卫国战争胜利80周年庆典
  • 河南省省长王凯在郑州调研促消费工作,走访蜜雪冰城总部
  • 见微知沪|优化营商环境,上海为何要当“细节控”自我加压?
  • 民生访谈|摆摊设点、公园搭帐篷、行道树飘絮,管理难题怎么解?
  • 金球看淡,不服就干!这是抬不起腿却昂着头的劳塔罗