【Linux】线程ID与互斥、同步(锁、条件变量)
作者主页: 作者主页
本篇博客专栏:Linux
创作时间 :2024年11月24日
线程ID及进程地址空间布局
先看一下这段代码:
运行一下:
运行这个代码之后,我们看到的这个很大的数字就是线程id,然后我们可以用ps -aL命令来查看一下:
这里面的第一串数字就是pid,第二串数字就是LWP,我们可以看到LWP跟线程id是不一样的。所以给用户提供的线程id,不是内核中的lwp,而是pthread库自己维护的一个值
通过这个代码:我们把上面的数字转换成十六进制,可以看出这是一个地址:
理解库
动态库在运行时被加载,动态库没被加载前在磁盘当中
pthread库本质也是一个文件
我们刚刚写的可执行程序,他也是一个文件,他也在磁盘当中,可执行程序内部用线程库来创建多线程。
程序运行的时候,会变成一个进程,加载到内存当中,内存中就有了该进程的代码和数据。创建线程的时候,我们要先把线程库加载到内存当中,然后再映射到该进程的地址空间才能用,映射要映射到堆栈之间的共享区,如果有多个多线程进程,只需要将共享取得代码经过页表映射到已经加载到内存的库,此时多个进程就可以使用同一个库里的方法来创建线程
Linux只维护轻量级进程,linux中的pcb里与执行流相关的属性都是轻量级进程的属性,所有的属性都是围绕lwp展开的。我们在用户层的概念是线程,要的是线程的id,与线程相关的内容在Linux中是没有的,它没有维护。所以这部分属性由库来进行维护。
为了更好的管理线程,创建线程时,库会为我们的每一个线程申请一个内存块(描述线程的相关结构体字段属性)。
未来要找一个线程的所有属性,只要找到线程控制块的地址即可。所以pthread_t id就是一个地址。
pthread_t类型的线程ID,本质就是线程属性集合的起始虚拟地址 ---- 在pthread库中维护。
有这些打印出来的值可以看出,全部变量是受所有线程所控制的
但如果我们这样去写的话:
如果我们想让两个线程各自私有一份变量,g++有一个编译选项 __thread
用__thread修饰这个全局变量即可。运行后,主线程和新线程gval的地址也不一样了。这种情况叫线程的局部存储,原始代码里只看到一个gval,但是他们用的是各自的gval。
这种情况只在Linux中有效。__thread只能用来修饰内置类型
线程简单封装
#pragma once
#include
#include
#include
namespace ThreadMoudle
{
// 线程要执行的方法,后面我们随时调整
typedef void (*func_t)(const std::string &name); // 函数指针类型
class Thread
{
public:
void Excute()
{
std::cout << _name << "