E2E UI 监控系统框架:Python + Selenium + Docker + GitHub Actions + Prometheus

核心内容摘要

ET框架深度技术解析:从架构原理到实战部署的完整指南
保姆级教程:手把手带你开发一个“一键复制标题+链接”的Chrome插件(附完整代码)

比较CVaR最优投资组合与均值-方差投资组合以及其他模型,包括全局最小方差(GMVP)和市场投资组合附Matlab代码

目录

CurrentThread.h

ThreadLocal 类的整体定位

逐模块拆解核心实现

关键细节深度解析

pthread_key_t 的核心语义与 __thread 对比

value() 懒创建逻辑核心易用性设计

静态 destructor 函数自动析构的关键

构造 / 析构函数的注意点

核心使用示例

设计亮点与

注意事项设计亮点

注意事项

CurrentThread.h先贴出完整代码再逐部分解释// 本源代码的使用受 BSD 风格许可证约束 // 该许可证可在 License 文件中查阅。

// // 作者陈硕 (chenshuo at chenshuo dot com) #ifndef MUDUO_BASE_THREADLOCAL_H #define MUDUO_BASE_THREADLOCAL_H #include muduo/base/Mutex.h // 提供 MCHECK 宏pthread 函数返回值检查 #include muduo/base/noncopyable.h// 不可拷贝基类 #include pthread.h // POSIX 线程库pthread_key_t 及线程局部存储操作函数 namespace muduo { // 线程局部存储TLS封装类不可拷贝 // 核心功能基于 pthread_key_t 实现为每个线程提供独立的 T 类型对象实例 // 线程退出时自动调用析构函数销毁该对象避免内存泄漏 templatetypename T class ThreadLocal : noncopyable { public: // 构造函数创建 pthread 键key并注册线程退出时的析构函数 ThreadLocal() { // pthread_key_create创建线程局部存储键 // 参数1输出创建的键 pkey_参数2析构函数线程退出时自动调用销毁该线程的 T 对象 MCHECK(pthread_key_create(pkey_, ThreadLocal::destructor)); } // 析构函数删除 pthread 键注意不会主动销毁各线程的 T 对象仅释放键本身 ~ThreadLocal() { // pthread_key_delete删除已创建的线程局部存储键 // 注若仍有线程持有该键关联的对象不会触发析构需依赖线程退出时的 destructor MCHECK(pthread_key_delete(pkey_)); } // 获取当前线程的 T 类型对象不存在则自动创建 // return 当前线程专属的 T 对象引用每个线程独立互不干扰 T value() { // pthread_getspecific获取当前线程与 pkey_ 关联的私有数据 T* perThreadValue static_castT*(pthread_getspecific(pkey_)); if (!perThreadValue) // 当前线程尚未创建 T 对象 { T* newObj new T(); // 创建新的 T 对象默认构造 // pthread_setspecific将新创建的 T 对象与当前线程的 pkey_ 关联 MCHECK(pthread_setspecific(pkey_, newObj)); perThreadValue newObj; // 更新指针指向新创建的对象 } return *perThreadValue; // 返回当前线程的 T 对象引用 } private: // 静态析构函数线程退出时由 pthread 自动调用销毁该线程的 T 对象 // param x 指向当前线程关联的 T 对象的指针 static void destructor(void *x) { T* obj static_castT*(x); // 转换为 T 类型指针 // 编译期静态检查确保 T 是完整类型已定义而非仅声明 // 若 T 是不完整类型如仅声明 class T;sizeof(T) 会报错-1 会导致数组长度非法编译失败 typedef char T_must_be_complete_type[sizeof(T) 0 ? -1 : 1]; T_must_be_complete_type dummy; (void) dummy; // 避免未使用变量警告 delete obj; // 销毁 T 对象释放内存 } private: pthread_key_t pkey_; // 线程局部存储键全局唯一每个线程通过该键关联独立的 T 对象 }; } // namespace muduo #endif // MUDUO_BASE_THREADLOCAL_H

ThreadLocal类的整体定位ThreadLocal是 Muduo 中面向对象、类型安全的线程局部存储TLS封装核心设计目标是解决__thread关键字的局限性__thread仅支持 POD 类型如 int / 指针且无法自动析构非 POD 类型如new出来的对象基于pthread_key_t实现支持任意 C 类型非 POD、带析构函数的类线程退出时自动析构对象避免内存泄漏懒创建线程首次调用value()时才创建对象而非线程启动时节省资源类型安全模板封装避免 void* 类型转换的不安全操作编译期检查类型合法性。

它是 Muduo 中 “每个线程独立持有一个对象” 场景的核心工具如每个线程独立的日志器、内存池、上下文对象弥补了__thread在复杂类型场景下的不足。

逐模块拆解核心实现templatetypename T class ThreadLocal : noncopyable // 禁止拷贝每个ThreadLocal对应一个pthread_key_t拷贝会导致重复析构 { public: // 构造创建pthread_key_t注册析构函数 ThreadLocal() { // pthread_key_create创建全局唯一的TLS键注册destructor为线程退出时的析构函数 MCHECK(pthread_key_create(pkey_, ThreadLocal::destructor)); } // 析构删除TLS键仅删除键不会触发析构函数 ~ThreadLocal() { MCHECK(pthread_key_delete(pkey_)); } // 核心接口获取当前线程的私有T对象懒创建 T value() { //

获取当前线程关联到pkey_的私有值首次调用为NULL T* perThreadValue static_castT*(pthread_getspecific(pkey_)); if (!perThreadValue) { //

首次调用创建T对象关联到当前线程的pkey_ T* newObj new T(); MCHECK(pthread_setspecific(pkey_, newObj)); perThreadValue newObj; } //

返回引用保证每个线程拿到自己的私有对象 return *perThreadValue; } private: // 静态析构函数线程退出时pthread库自动调用注册在pthread_key_create中 static void destructor(void *x) { // 转换为T*删除对象释放内存调用T的析构函数 T* obj static_castT*(x); // 编译期检查确保T是完整类型避免前向声明的不完整类型导致delete出错 typedef char T_must_be_complete_type[sizeof(T) 0 ? -1 : 1]; T_must_be_complete_type dummy; (void) dummy; delete obj; } private: pthread_key_t pkey_; // TLS键全局唯一每个线程通过它访问自己的私有值 };

关键细节深度解析

pthread_key_t的核心语义与__thread对比pthread_key_t是 POSIX 定义的运行时线程局部存储键其核心特性与__thread形成互补特性pthread_key_tThreadLocal__threadCurrentThread实现层面运行时pthread 库编译期编译器 / 内核访问效率稍慢哈希表查找极快直接访问线程私有内存支持类型任意 C 类型自动析构仅 POD 类型int / 指针等析构机制线程退出时自动调用注册的析构函数无非 POD 类型需手动析构内存管理自动 new/delete无泄漏手动管理易泄漏适用场景复杂类型类对象、需要析构简单类型tid、线程名核心逻辑pthread_key_t是一个 “全局索引”每个线程有一个 “键 - 值” 哈希表通过这个全局索引每个线程能查到自己的私有值T*且线程退出时pthread 库会遍历该线程的哈希表对每个键调用注册的析构函数。

value()懒创建逻辑核心易用性设计首次调用pthread_getspecific(pkey_)返回 NULL →new T()创建对象 →pthread_setspecific将对象关联到当前线程的pkey_→ 返回对象引用后续调用直接从当前线程的哈希表中获取已创建的对象无需重复创建返回引用避免值拷贝保证线程操作的是自己的唯一对象且支持修改如threadLocal.value().setXXX()。

静态destructor函数自动析构的关键调用时机当线程正常退出时pthread 库会自动调用pthread_key_create注册的destructor函数传入该线程关联到pkey_的值T*类型安全检查typedef char T_must_be_complete_type[sizeof(T) 0 ? -1 : 1]; T_must_be_complete_type dummy; (void) dummy;这是编译期断言的技巧如果 T 是 “不完整类型”如前向声明的class A;sizeof(T)会编译报错数组长度为 - 1避免因类型不完整导致delete obj时的未定义行为析构语义delete obj会调用 T 的析构函数保证复杂类型如std::string、自定义类的资源正确释放。

构造 / 析构函数的注意点pthread_key_create创建的是 “全局键”进程内所有线程可见但每个线程对这个键的取值是独立的pthread_key_delete仅删除 “键本身”不会触发析构函数也不会删除线程关联的值 —— 析构函数仅在线程退出时由 pthread 库调用noncopyable继承禁止拷贝ThreadLocal对象 —— 每个ThreadLocal对应一个pthread_key_t拷贝会导致两个对象管理同一个键析构时重复调用pthread_key_delete引发未定义行为。

核心使用示例#include muduo/base/ThreadLocal.h #include string #include iostream // 定义每个线程独立的字符串对象 muduo::ThreadLocalstd::string tlsString; void threadFunc() { // 首次调用创建std::string对象赋值为hello tlsString.value() hello, thread std::to_string(muduo::CurrentThread::tid()); // 打印当前线程的私有对象 std::cout Thread muduo::CurrentThread::tid() : tlsString.value() std::endl; // 线程退出时destructor自动delete std::string对象释放内存 } int main() { // 主线程设置自己的私有值 tlsString.value() hello, main thread; std::cout Main thread: tlsString.value() std::endl; // 创建子线程 muduo::Thread t1(threadFunc); muduo::Thread t2(threadFunc); t

start(); t

start(); t

join(); t

join(); return 0; }输出示例Main thread: hello, main thread Thread 12345: hello, thread 12345 Thread 12346: hello, thread 12346关键特性主线程和两个子线程的tlsString是独立对象互不干扰且线程退出时std::string会自动析构无内存泄漏。

设计亮点与

注意事项设计亮点类型安全模板封装避免 void* 裸指针转换编译期检查类型完整性懒创建线程首次使用时才创建对象节省内存尤其线程多但并非所有线程都使用该对象的场景自动析构注册 pthread 析构函数保证线程退出时对象正确释放避免内存泄漏极简接口仅暴露value()接口使用简单符合 “最小接口原则”。

注意事项性能权衡pthread_getspecific/setspecific是运行时哈希表查找效率低于__thread简单类型优先用__thread线程退出时机析构函数仅在线程正常退出时调用若线程被强制终止如pthread_cancel可能不会触发析构完整类型要求T 必须是完整类型不能是前向声明否则编译报错。

成全动漫第6季在线观看免费高清版-成全动漫第6季在线观看免费高清版应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123