muduo学习笔记5——线程封装

2023-11-14

  • 线程标识符

  • pthread_self

  • gettid

  • __thread, gcc内置的线程局部存储设施

  • __thread只能修饰POD类型, plain old data

  • pthread_atfork

线程标识符

Linux中,每个进程有一个pid,类型为pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型为pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP:轻量级进程),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。

有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread id,而只能使用该线程的真实pid,称为tid。
函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取

return syscall(SYS_gettid)

但因为使用线程调用开销很大,所以我们需要对所获取的tid做一个缓存,防止每次都使用系统调用,从而提高获取tid的效率

muduo库中线程类的实现,采用的是基于对象的方式来实现的
在这里插入图片描述

started_表示线程是否已经启动
pthreadId_:进程中线程id
tid_真实线程id
func_该线程要回调的函数
name_线程名称
numCreated已经创建的线程个数,是一个原子整数类

代码还是很清楚的, Thread.cc
在这里插入图片描述
其中CurrentThread中实现了对线程真实tid的缓存
在这里插入图片描述
注意一下__thread修饰的变量是线程局部存储的, 且只能修饰POD类型,不能修饰class类型,因为无法自动调用构造函数和析构函数
在这里插入图片描述

__thread, gcc内置的线程局部存储设施

POD类型 (plain old data),与C兼容的原始数据,例如结构和整型等C语言中的类型是POD类型,但带有用户定义的构造函数或虚函数的类则不是

__thread string t_obj1(“hello”);    // 错误,不能调用对象的构造函数
__thread string* t_obj2 = new string;   // 错误,指针类型是POD类型,但是初始化必须用编译期常量,不能是运行期的
__thread string* t_obj3 = NULL; // 正确,但是需要手工初始化并销毁对象

__thread变量在每一个线程有一份独立实体,各个线程的值互不干扰。可以用来修饰那些带有全局性且值可能变,但是又不值得用全局变量保护的变量。用一个例子来理解它的用法。

#include <pthread.h>
#include <iostream>
#include <unistd.h>

using namespace std;

//__thread int var = 5;
int var = 5;

void *worker1(void* arg);
void *worker2(void* arg);

int main()
{
        pthread_t p1, p2;

        pthread_create(&p1, NULL, worker1, NULL);
        pthread_create(&p2, NULL, worker2, NULL);
        pthread_join(p1, NULL);
        pthread_join(p2, NULL);

        return 0;
}

void *worker1(void* arg)
{
        cout << ++var << endl;
}

void *worker2(void* arg)
{
        cout << ++var << endl;
}

/**
 * 使用__thread关键字,输出为: 
 *                         6
 *                         6 个线程的值互不干扰, 跟全局变量?
 * 
 * 不使用__thread关键字,输出为:
 *                         6   
 *                         7
 * /

pthread_atfork()函数

在这里插入图片描述

#include <pthread.h>
int pthread_atfork(void (*prepare)(void), 
                    void (*parent)(void), 
                    void (*child)(void));

在调用fork时,内部创建子进程之前在父进程中会调用prepare,内部创建子进程成功后,父进程会调用parent ,子进程会调用child这就是pthread_atfork()的作用, 因为在fork之前可能有多个线程,有可能是在主线程中调用也有可能是在子线程中调用, 如果fork()是在子线程中调用得到一个新进程,新进程就只有一个执行序列,只有一个线程(调用fork的线倍继承下来),用pthread_atfork()来可以避免这种情况

对于编写多线程程序来说,最好不要调用fork(),即不要编写多线程多进程程序,因为Linux的fork()只克隆当前线程的thread of control, 不克隆其他线程。 fork()之后,除了当前线程之外,其他线程都消失了,也就是说,不能够一下子fork()和父进程一样的多线程子进程

fork()之后子进程中只有一个线程,其他线程都小时了,这就曹正一个危险的局面:其他线程可能正好位于临界区指内,持有了某个锁,而它忽然死亡,再也没有机会去解锁了。如果子进程试图再对同一个mutex加锁,就会死锁

那我们调用atfork()的话就可以在fork之前,即创建子进程之前去解锁,那样拷贝下来的就是解锁的,就不会死锁了

∴ 父进程在创建一个子进程的时候,指挥复制当前线程的执行状态,其他线程不会复制,因此子进程会处于死锁的状态

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

muduo学习笔记5——线程封装 的相关文章

随机推荐

  • 一百、Kettle(9.3.0)连接ClickHouse

    注意 低版本的kettle即使装ClickHouse驱动包后也不一定支持ClickHouse数据库连接 具体kettle从什么版本开始支持ClickHouse没测试过 只有高版本的kettle在安装ClickHouse驱动包后才支持Clic
  • 关于Winsows安装baselines的问题

    关于Winsows安装baselines的问题 windows是否可以使用baselines 根据GitHub上关于baselines的介绍 只有Linux和MAC OS给了配置说明 用pip在windows上安装的baselines只有最
  • HTML获取当前选中的li标签

    获取该class下的li标签 layui tab title li click function li标签下标默认为0 var liindex this index
  • foreach跳出本次/当前循环与终止循环方法及switch跳出方法

    目录 1 普通for循环 2 java中的foreach循环 3 js中的foreach循环 4 switch 1 普通for循环 continue 当满足某个条件时 想要跳出本次循环继续执行下次循环 break 满足某个条件的时候 终止f
  • 遗传算法优化BP神经网络的原理是什么

    遗传算法优化BP神经网络的原理是通过进行大量重复的试验 使用遗传算法来改进和优化神经网络的参数 以使神经网络能够更好地完成特定任务 遗传算法通过进化算法对神经网络中的参数进行重新调整 从而获得更好的性能
  • SQL中的CASE WHEN使用 .

    Case具有两种格式 简单Case函数和Case搜索函数 简单Case函数 CASE sex WHEN 1 THEN 男 WHEN 2 THEN 女 ELSE 其他 END Case搜索函数 CASE WHEN sex 1 THEN 男 W
  • 萤石摄像头RTSP流获取(黑屏解决)

    前言 在获取萤石摄像头RTSP视频流时 视频流获取不成功 黑屏并且一直显示缓冲中 下面对获取过程中查阅的资料和解决方案做一下汇总 打开RTSP 在萤石云视频APP中打开RTSP 我的 工具 局域网设备预览 开始扫描 选择摄像头 设置 更多设
  • 本地代码上传github

    怎么将新创建的本地代码上传到github上 这里简单的记录一下 我喜欢使用命令行 这里全用命令行来实现 不了解git命令的可以去了解下 1 先在github中创建仓库 2 回到你本地项目路径下右击打开git 没有的自行安装即可 3 初始化
  • ios.js?v=7c33aa19:1183 Uncaught (in promise) AxiosError {message: ‘Request failed with status code 4

    ios js v 7c33aa19 1183 Uncaught in promise AxiosError message Request failed with status code 404 name AxiosError code E
  • mysql中 or的使用方法,mysql条件查询中与or同时使用时的注意事项!!

    我们在日常的crud开发中 经常会遇到查询数据不是预期效果的问题 但是有感觉自己的查询语句没什么问题呀 怎么会出错呢 今天我也中招了 就很烦 sql如下 在查询语句中我们有一个条件是year 2021 但是查询结果还包含了2020的数据 这
  • Windows WSL配置ubuntu环境并登录

    一 什么是WSL wsl即适用于Windows的Linux子系统 Windows subsystem for Linux 二 Windows WSL配置ubuntu环境 1 管理员运行cmd 执行以下命令启用 适用于 Linux 的 Win
  • Codeforces Round 739 (Div. 3)

    A Dislike of Threes AC代码 include
  • Git的版本和分支管理

    1 http blog csdn net xiahouzuoxin article details 9393119 2 http blog csdn net xiahouzuoxin article details 9398629 3 ht
  • Qt在linux系统中执行shell命令

    在linux系统下 Qt执行shell命令的方式有3种 1 QProcess execute ls 2 system ls 3 QProcess process new QProcess process gt start ls 注1 以上3
  • 解决ubuntu20搜狗输入法输入不了中文问题

    解决在ubuntu上安装好搜狗输入法后无法输入中文 首先按照官网的安装步骤安装 Ubuntu搜狗输入法安装指南 注意不要忘记安装依赖 输以下命令进行安装 sudo apt install libqt5qml5 libqt5quick5 li
  • 接口测试的测试用例该怎么写呢?

    作者 字节开发测试 链接 https www zhihu com question 305629217 answer 2530044958 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 一 什么是接口 接口
  • Python的exec

    目录 exec 简单使用 动态执行简单的字符串代码 动态执行较复杂的代码 执行文件中的Python代码 在exec中传参 使用中遇到的问题 参考 exec 简单使用 个人比较喜欢用Python里面的exec 可以用来动态执行字符串代码 在f
  • bootstrap方法_自助法(bootstrap)在统计检验中的应用及R语言实现过程

    Bootstrap 自助法 自举法 是非参数统计中一种重要的估计统计量方差 进而进行区间估计的统计方法 Bootstrap通过对给定数据集进行有放回的重抽样以创建多个模拟数据集 生成一系列待检验统计量的经验分布 可以计算标准误差 构建置信区
  • 随机数与简单的周期运动轨迹图案

    背景 概率论的书上有这样一个示例 设想某人在平面上从零点出发 手持一个均匀四面体 四面分别标有1 2 3 4 每个面代表一个方向 东南西北 他随意抛出后 按照这个方向走一单位长度 若干次后观测他走过的路线的轨迹 由此你有什么联想 联想倒是没
  • muduo学习笔记5——线程封装

    线程标识符 pthread self gettid thread gcc内置的线程局部存储设施 thread只能修饰POD类型 plain old data pthread atfork 线程标识符 Linux中 每个进程有一个pid 类型