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

时间:2024-10-22 07:00:54

目录

基本概念

重新理解进程

线程真实存在吗?

问题解答

线程资源

线程控制

线程创建

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

如何看到线程函数返回

线程查询

线程等待

线程终止

线程分离


基本概念

线程(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)-****博客

(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的,但是依旧属于进程内部,只是不需要等待了而已;分离不等于分家;                                            

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