【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;
// }
相关文章
|
17天前
|
消息中间件 存储 缓存
【嵌入式软件工程师面经】Linux系统编程(线程进程)
【嵌入式软件工程师面经】Linux系统编程(线程进程)
29 1
|
3天前
|
安全 Linux 数据安全/隐私保护
探索Linux命令newuidmap:用户ID映射的利器
`newuidmap`是Linux工具,用于在用户命名空间中设定UID映射,支持容器安全。它允许限定容器内进程的主机系统权限,确保数据安全和隔离。通过映射文件或命令行参数定义UID映射,提供灵活性和安全性。例如,为Docker容器设置映射,使进程能访问特定UID的数据文件。使用时需注意映射准确性、权限控制和避免映射过多UID。与其他工具如`newgidmap`配合使用以增强用户命名空间支持。
|
7天前
|
API
linux---线程互斥锁总结及代码实现
linux---线程互斥锁总结及代码实现
|
8天前
|
Linux 数据处理 数据库
深入解析Linux命令id:理解用户身份与权限
`id`命令在Linux中用于显示用户身份(UID, GID和附加组)。它查看系统用户数据库获取信息。参数如`-u`显示UID,`-g`显示GID,`-G`显示附加组,结合`-n`显示名称而非ID。用于确认命令执行者身份,确保权限正确。在脚本中使用时注意权限管理,遵循最小权限原则。
|
7天前
|
Linux API
Linux线程总结---线程的创建、退出、取消、回收、分离属性
Linux线程总结---线程的创建、退出、取消、回收、分离属性
|
7天前
|
API
Linux---线程读写锁详解及代码实现
Linux---线程读写锁详解及代码实现
|
17天前
|
消息中间件 安全 Java
【嵌入式软件工程师面经】Linux多进程与多线程
【嵌入式软件工程师面经】Linux多进程与多线程
17 1
|
20天前
|
Java Linux Shell
Linux环境下,让Jar项目多线程部署成为可能
Linux环境下,让Jar项目多线程部署成为可能
13 1
|
1月前
|
设计模式 安全 Java
【Linux 系统】多线程(生产者消费者模型、线程池、STL+智能指针与线程安全、读者写者问题)-- 详解
【Linux 系统】多线程(生产者消费者模型、线程池、STL+智能指针与线程安全、读者写者问题)-- 详解
|
1月前
|
安全 算法 Linux
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(下)
【Linux 系统】多线程(线程控制、线程互斥与同步、互斥量与条件变量)-- 详解(下)