【Linux】线程ID

大致草稿——————————

思维导图

学习目标

一、线程ID的理解

1.1 引出对tid的理解

我们先来创建一个线程复习一下线程的函数:

pthread_t tid;
// 创建一个线程
pthread_create(&tid, nullptr, threadrun, (void*)"thread-1");
// 打印出新线程的tid
std::cout << "new pthread tid:" << tid << std::endl;
// 进行线程的暂停
pthread_join(tid, nullptr);
// 线程执行的任务函数
void* threadrun(void* args)
{
    std::string name = static_cast<const char*>(args);
    while (true)
    {
        std::cout << name << " is runing, tid:" << pthread_self() << std::endl;
        sleep(1);
    }
}
// 将一个数字转换为十六进制的字符串
std::string ToHEX(pthread_t tid)
{
    char id[128];
    snprintf(id, sizeof id, "0x%lx", tid);
    return id;
}

我们可以通过代码执行结果和ps -aL来查看这个线程的lwp和线程ID是不同的。 

       通过上述现象,我们发现这个线程的Iwp,给用户提供的线程ID是不同的,这个两个数字不是一个东西,线程ID是由pthread库自己维护一个值。举个例子,我们的身份证、学号是由谁给我们发送的,是由管理我们的对象生成的,因此在这个库中自然也是要对线程的管理。

总结:

  • 线程ID是一个地址
  • pthread库提供唯一的线程ID,并且对线程进行管理

1.1.1 理解库: 

       pthread库是一个文件,我们自己写的可执行程序也是一个文件,他们都存放在磁盘中。我们需要将可执行程序加载到内存中,将数据和代码加载到内存中,CPU区进行调度,在这个客户可执行程序中,我们如果想要创建线程,需要使用pthread函数,需要将这个pthread库加载到内存中,映射到进程的地址空间。

1.1.2 库如何做到对线程进行管理?

线程的局部变量:

在全局变量中,所有的线程都可以看到这个局部变量,如果我们使用__thread来修饰全局变量,会使所有的线程在对应的线程的局部变量中都有一份gval打印出来的地址也是不一样的。

线程有一个属性:栈的大小(pthread_attr_t)

tid是一个虚拟地址,在我们的地址空间中一个线程对应的一个线程控制块。线程的ID本质是线程控制块的地址。 

二、对线程的封装

       在学习完对tid的理解后,我们来进行学习对线程的封装,用类将线程的几个函数和属性封装起来。

// 线程的属性
std::string _name;  // 线程的名字
pthread_t _tid;     // 线程ID
bool is_running;    // 线程是否运行
func_t _func;       // 新线程所实行的函数
void Excute();

mThread(const std::string name, func_t func);
     : _name(name), _func(func)
  
static void *ThreadRoutine(void *args); ;
        
bool Start();
        
std::string status();
        
void Stop();
      
void Join();
        
std::string Name();
        
~mThread();  

接下来,我们来封装一下其函数:

2.1.1 构造函数

mThread(const std::string name, func_t func)
    : _name(name), _func(func)
{
    std::cout << "create " << name << " done" << std::endl;
}

2.1.2 开始函数

void Excute()
{
    std::cout << _name << " is running" << std::endl;

    is_running = true;
    _func(_name);
    is_running = false;
}

// 类内函数隐含的隐藏了this指针
static void *ThreadRoutine(void *args) // 新线程都会执行
{
    //_func(_name);
    mThread *self = static_cast<mThread *>(args); // 获得了我们对应的当前对象
    self->Excute();
    return nullptr;
}

bool Start()
{
    int n = ::pthread_create(&_tid, nullptr, ThreadRoutine, this);
    if (n != 0)
        return false;
    return true;
}

2.1.3 暂停函数

void Stop()
{
     if (is_running)
     {
         ::pthread_cancel(_tid);
         is_running = false;
         std::cout << _name << " Stop" <<std::endl;
     }
}

2.1.4 取消函数

void Join()
{
    ::pthread_join(_tid, nullptr);
    std::cout << _name << " Join" << std::endl;
}

2.1.5 测试代码

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include "Thread.hpp"

using namespace Mypthread;

void Print(const std::string &name)
{
    int cnt = 1;
    while (true)
    {

        std::cout << "name:" << name << " is runing, cnt:" << cnt++ << std::endl;
        sleep(1);
    }
}

int main()
{
    std::vector<mThread> mThreads;
    for(int i = 0; i < 10; i++)
    {
        std::string name = "thread-" + std::to_string(i + 1);
        mThreads.emplace_back(name, Print);
        sleep(1);
    }
    // 统一启动
    for(auto& k : mThreads)
    {
        k.Start();
    }

    sleep(10);

    // 统一停止
    for(auto& k : mThreads)
    {
        k.Stop();
    }

    // 统一取消
    for(auto& k : mThreads)
    {
        k.Join();
    }
    return 0;
}

// int main()
// {
//     // 线程的开始
//     const std::string name = "thread-1";
//     mThread t(name, Print);
//     // std::cout << "status" << t.status() << std::endl;
//     t.Start();
//     std::cout << t.Name() << " ,status:" << t.status() << std::endl;
//     sleep(10);
//     std::cout << t.Name() << " ,status:" << t.status() << std::endl;

//     t.Stop();
//     sleep(1);
//     std::cout << t.Name() << " ,status:" << t.status() << std::endl;

//     t.Join();
//     std::cout << t.Name() << " ,status:" << t.status() << std::endl;
//     return 0;
// }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

加油,旭杏

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

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

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

打赏作者

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

抵扣说明:

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

余额充值