【Linux】线程ID

简介: 【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,并且对线程进行管理

理解库:

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

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

线程的局部变量:

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

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

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

二、对线程的封装

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

// 线程的属性
std::string _name;
pthread_t _tid;
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;
// }
相关文章
|
4月前
|
算法 Unix Linux
linux线程调度策略
linux线程调度策略
95 0
|
2月前
|
资源调度 Linux 调度
Linux C/C++之线程基础
这篇文章详细介绍了Linux下C/C++线程的基本概念、创建和管理线程的方法,以及线程同步的各种机制,并通过实例代码展示了线程同步技术的应用。
34 0
Linux C/C++之线程基础
|
2月前
|
安全 Linux
Linux线程(十一)线程互斥锁-条件变量详解
Linux线程(十一)线程互斥锁-条件变量详解
|
4月前
|
存储 设计模式 NoSQL
Linux线程详解
Linux线程详解
|
3月前
|
Linux API
Linux内核中的两种ID分配方式
Linux内核中的两种ID分配方式
|
4月前
|
缓存 Linux C语言
Linux线程是如何创建的
【8月更文挑战第5天】线程不是一个完全由内核实现的机制,它是由内核态和用户态合作完成的。
|
4月前
|
负载均衡 Linux 调度
在Linux中,进程和线程有何作用?
在Linux中,进程和线程有何作用?
|
4月前
|
缓存 Linux C语言
Linux中线程是如何创建的
【8月更文挑战第15天】线程并非纯内核机制,由内核态与用户态共同实现。
|
6月前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
6月前
|
安全 Linux 数据安全/隐私保护
探索Linux命令newuidmap:用户ID映射的利器
`newuidmap`是Linux工具,用于在用户命名空间中设定UID映射,支持容器安全。它允许限定容器内进程的主机系统权限,确保数据安全和隔离。通过映射文件或命令行参数定义UID映射,提供灵活性和安全性。例如,为Docker容器设置映射,使进程能访问特定UID的数据文件。使用时需注意映射准确性、权限控制和避免映射过多UID。与其他工具如`newgidmap`配合使用以增强用户命名空间支持。