【Linux】线程基本概念,线程控制

目录

基本概念

重新理解进程

线程真实存在吗?

问题解答

线程资源

线程控制

线程创建

如何全面看待线程函数传参

如何看到线程函数返回

线程查询

线程等待

线程终止

线程分离


基本概念

线程(thread)是指在单个进程内,多路并行执行的创建和管理单元;

重新理解进程

在没有学习线程的时候,我们学的进程=内核数据结构+程序的代码和数据;每个进程系统都会为其分配task_struct(PCB),mm_struct(虚拟地址空间),页表来描述和管理进程;

上面的整个才是进程,进程是程度系统资源分配的基本实体;

而线程其实就是进程内的执行流;和之前的进程对比,之前的进程就是内部只有一个执行流的进程!

线程真实存在吗?

在windows中存在真正的进程tcb,而在Linux中并不存在真正的进程,Linux中是用进程来模拟线程!!!

因为复原PCB,同PCB来统一表示执行流,这样的话就不需要为线程单独设计数据结构和调度算法了;像进程一样,线程在程序中有独立,并发的执行路径,每个线程都有它自己私有的栈空间,自己的程序计数器,自己的寄存器,但是他们共享全局数据区,文件描述符等;

问题解答

既然线程用PCB来模拟,那CPU会不会区分task_struct是线程还是进程呢?

不做区分,CPU统一将他们看做执行流;Linux中执行流统一被称为轻量级进程;

那么,既然有了多进程,为什么要有多线程呢?

  • 进程的创建成本高,创建线程的成本低
  • 线程调度成本低
  • 删除线程成本低

为什么说线程调度成本低呢?

主要原因是在进程切换时,由于线程共享进程的内存空间和资源,cpu的cache中数据往往有效,因此减少了因cache不命中导致的缺页中断开销。

既然线程这么好用,为什么要有进程呢?

虽然线程有很多优势,但也不是毫无代价的.事实上,有些最可怕的bug就是由多线程引起的.设计,编写,理解以及最重要的----调试多线程程序,这些复杂度都是远远高于单个线程的进程. 最主要的原因:多个虚拟的处理器,但是只有一个虚拟化内存实例,当一个线程同步失败,就会使整个进程运行出错以及程序崩溃;

线程资源

线程共享资源:

  • 进程地址空间
  • 文件描述符表
  • 信号处理方式
  • 当前工作目录
  • 用户ID和组ID

线程私有资源:

  • 线程ID
  • 私有栈空间(重要)
  • 一组寄存器(重要)
  • 程序计数器
  • errno变量
  • 调度优先级
  • 信号屏蔽字

线程控制

线程创建

pthread_create:创建线程

复制代码
#include <iostream>
#include <unistd.h>
#include<pthread.h>
using namespace std;

void *pthreadRun(void *args)
{
    while(true)
    {

        cout<<"I am "<<(const char *)args<<endl;
        sleep(1);
    }
    return nullptr;
}
int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,pthreadRun,(void *)"thread-1");

    while(true)
    {
        cout<<"I am main thread"<<endl;
        sleep(1);
    }
    return 0;
}

运行结果:

如何全面看待线程函数传参

给线程传参可以是任意类型,也可以是类对象类型;

void* 指针可以指向任意类型的数据;

具体的void*内容可以看下面的文章:

c语言---指针(1)-CSDN博客

(1)

运行结果:

(2)不推荐

运行结果:

既然不推荐的话,怎么优化呢?

复制代码
    ThreadData *td =new ThreadData();
    td->name="thread";
    td->num="1";
如何看到线程函数返回
  • 只考虑正确的返回,不考虑异常,因为异常了,整个进程就崩溃了,包括主线程
  • 可以传任意参数,也可以是任意类对象

运行结果:

线程查询

怎么查询线程有没有创建成功呢?

ps -aL:查询线程

ps ajx:查询进程

我们会发现同一个进程下创建的多线程的PID是一样的,但是每个线程的LWP是不一样的;其实OS调度时看到是LWP并不是PID,我们在没有学习线程的时候说的是PID,和现在的说法不是冲突了吗?其实并不是我们之前创建的不管是多进程还是单进程,在进程中都是只有一个执行流的,那是PID和LWP是相同的,所以我们之前所说的PID,其实看到还是LWP只不过LWP和PID一样;学完线程后,我们以后就要说LWP了;

怎么查询线程的LWP呢?

复制代码
void *pthreadRun(void *args)
{
    cout<<"tid :"<<pthread_self()<<endl;
    while(true)
    {

        cout<<"I am "<<(const char *)args<<endl;
        sleep(1);
    }
    return nullptr;
}

运行结果:

线程等待

我们期望主线程先退出还是新线程最后退出? ----> 当然是主线程了,那如何保证main thread最后退出呢?

join来保证,这时就要用到pthread_join来等待新线程;

复制代码
int main()
{
    pthread_t tid;
    int n=pthread_create(&tid,nullptr,pthreadRun,(void *)"thread-1");
    if(n!=0)
    {
        cout<<strerror(errno)<<endl;
        return 1;
    }

    //期望谁最后退出?主线程,还是新线程  -->main thread 如何保证?
    n = pthread_join(tid,nullptr);
    if(n==0)
    {
        cout<<"main thread wait sucess"<<endl;
    }

    return 0;
}

运行结果:

线程终止

在进程的学习时,我们学过进程的终止有:

  • return
  • exit
  • 信号

那线程的终止有哪些呢?

1、自然退出:线程函数return

2、pthread_exit() 我们不能用exit()来进行线程的退出,如果一个线程退出时,用了exit,那么整个进程就会退出,因为exit是用来终止进程的;

3、pthread_cancel :取消一个线程

线程分离

既然进程有SIGCHLD信号可以让进程不等待,那线程有没有类似的可以让线程也不等待?

当然有了,就是pthread_detach;

  1. 一个线程被创建默认是joinable的,必须被join
  2. 如果一个线程被分离,线程的工作状态处于分离状态,那么就不需要/不必要被join的,但是依旧属于进程内部,只是不需要等待了而已;分离不等于分家;

以上就是线程的基本概念,线程控制的全部内容!!!

相关推荐
PatrickYao04225 小时前
Hydro OJ部署完全指南!
服务器·oj·hydro·在线评测
小政同学5 小时前
【NFS故障】共享的文件无法执行
linux·运维·服务器
不会写DN5 小时前
受保护的海报图片读取方案 - 在不公开静态资源目录下如何获取静态资源
服务器
AI木马人5 小时前
3.【Prompt工程实战】如何设计一个可复用的Prompt系统?(避免每次手写提示词)
linux·服务器·人工智能·深度学习·prompt
lwf0061645 小时前
导数学习日记
学习·算法·机器学习
ch3nyuyu6 小时前
Ubuntu(乌班图)基础指令
linux·运维·网络
qeen876 小时前
【编程日记】现阶段总结
学习
minglie16 小时前
gcc编译器汇总
linux
挽安学长6 小时前
保姆级教程,通过GACCode使用Claude Code Desktop!
运维·服务器
firstacui7 小时前
MGRE实验
运维·服务器·网络