Linux多线程——线程的概念和控制

线程的概念

线程是我们经常听到的一个概念,他和进程有什么关系呢

从操作系统课本里我们可能听说过,线程是一个微缩版的进程,他拥有TCB,不会被分配资源,是CPU进行调度的单位

我们其实可以更直观的理解,程序中的一个执行路线我们就可以称之为线程,也可以说是执行流

那么一个进程他的执行路线至少有一个,也就算做是一个线程,这个进程本身也可以创建分支线程,那么原来的这个进程也就叫做主线程

在Linux中,线程其实没有自己的TCB,而是和进程公用PCB,内存空间也是共享的

因此在Linux中线程其实是要比进程更加轻量化的

每个线程都拥有自己的PCB,但都是自己从主线程中写时拷贝来的

在CPU的视角来看,他的所调度的所有单位都是PCB,是同一个进程,CPU也无法分辨他运行的是线程还是进程

进程和线程对比

线程其实是被CPU调度运行的的基本单位,因为一个CPU只能运行一个执行流

而进程是操作系统分配资源的基本单位,也就是说这个进程和他所属的线程内存空间全部共享,一个全局变量,不同线程之间也能共享

线程也拥有自己的特征数据,否则就无法对线程进行管理了

线程ID,栈区资源,信号屏蔽字,调度优先级

共享的资源和环境有

文件描述符表,信号处理方式,工作目录,用户ID,组ID

我们可以通过ps -aL查看线程ID

请添加图片描述

LWP就是对应进程ID的线程ID

线程的控制

创建线程与分配任务

第三方POSIX线程库在编译时需要引头文件pthread.h,编译选项需要链接库-lpthread

请添加图片描述

一共有四个参数,第一个是线程ID,第二个是选项,目前只设置为空指针即可,第三个选项是需要让新线程走的执行流,第四个是传递给其中的参数

需要注意的是,这个执行流的函数指针是固定的

使用示例

定义参数类

using Tfunc = std::function<void()>;

class TData
{
public:
    TData(const std::string str, const uint64_t time, Tfunc f)
        :TName(str), CreatTime(time), func(f)
    {}
public:
    std::string TName; // 线程名称
    uint64_t CreatTime; // 时间戳
    Tfunc func; // 执行的回调函数
};

void Print()
{
    std::cout<<"线程执行的任务函数"<<std::endl;
}

定义执行流

void* TRountine(void* args)
{
    TData* td = static_cast<TData*>(args); // 安全强制转换
    while(true)
    {
        std::cout<<"name:"<<td->TName<<std::endl;
        std::cout<<"create time:"<<td->CreatTime<<std::endl;
        td->func();
        sleep(1);
    }
    return nullptr;
}

创建参数包,创建子进程

int main()
{
    pthread_t tid;
    TData* TD = new TData("thread 1", (uint64_t)time(nullptr), Print);
    pthread_create(&tid, nullptr, TRountine, TD);

    while(true)
    {
        std::cout<<"这里是主线程"<<std::endl;
        sleep(3);
    }
    return 0;
}

请添加图片描述

手动创建多线程的话,我们可以使用vector对pthread_t进行保存即可

需要注意的是pthread_t和LWP是不同的,除了使用pthread_create里面的第一个输出型参数进行获取,还可以使用pthread_self获取自己的线程id

这个pthread_t的id的本质其实是一个地址

在多线程情况下,一个线程出现中断异常,整个进程都会退出,因为CPU不认识线程!每一种信号的处理方式都是共享的

线程终止

第一种线程终止的方式就是当新线程把自己的有效代码运行完成之后,他就会自动终止,和子进程的逻辑是相同的

如果直接调用exit退出的话,整个进程会直接退出

除此之外我们可以调用pthread_exit让新线程退出

请添加图片描述

这里传递的参数我们直接传nullptr即可

线程等待

线程默认是需要被等待的

当线程退出,没有被等待,就会导致类似进程的僵尸问题

我们可以用pthread_join来等待线程退出

请添加图片描述

例如可以这样使用

pthread_join(tid, nullptr);

效果就类似于waitpid

成功返回0,失败返回错误码

获取的线程返回值是通过第二个参数传递出来的,因为create规定的函数指针类型返回值是void*,因此想要获得这个返回值,就要传递void**进去

那么返回值也可以设计一个类了

线程分离

因为线程出错了其实是影响到整个进程的,所有返回值的意义其实不大,那么要让主线程一直等待就是不合算的事情了,所以就有了线程分离

int pthread_detach(pthread_t thread);

我们可以这样让当前线程和主线程脱离关系pthread_detach(pthread_self());

pthread线程库

线程ID的本质是一个地址,而pthread是一个动态的第三方库

当我们进行编译运行的时候,这个库就会被映射到进程地址空间的共享区里

而进程ID的地址本质就是pthread这个库里,线程集合的其实地址

线程需要维护自己的战区,其实就是pthread来维护的

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

栖林_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值