26.线程概念与控制(三)
这种stack不能动态增长,一旦用尽就没了,这是和生成进程的fork不同的地方。对于 Linux 进程或者说主线程,简单理解就是main函数的栈空间,线程栈⼀般是调用glibc/uclibc等的 pthread。,它其实是在进程的地址空间中map出来的⼀块内存区域。创建的线程,在文件映射区(或称之为共享区)。模拟C++封装原生线程库pthread。(发送段错误信号给该进程)。
·
1.线程栈
对于 Linux 进程或者说主线程,简单理解就是main函数的栈空间,在fork的时候,实际上就是复制了父亲的 stack 空间地址,然后写时拷贝(cow)以及动态增长。如果扩充超出该上限则栈溢出会报段错误(发送段错误信号给该进程)。进程栈是唯一可以访问未映射页而不一定会发生段错误---超出扩充上限才报。例子:栈位于非标准内存区域(如自定义内存分配器)触发条件:栈未使用系统默认的栈区域(如高地址向下增长),而是通过手动分配内存模拟栈行为。然而对于主线程生成的子线程而言,其 stack 将不再是向下生长的,而是事先固定下来的。线程栈⼀般是调用glibc/uclibc等的 pthread 库接口 pthread_create 创建的线程,在文件映射区(或称之为共享区)。这种stack不能动态增长,一旦用尽就没了,这是和生成进程的fork不同的地方。对于子线程的 stack ,它其实是在进程的地址空间中map出来的⼀块内存区域总结:![]()
2.线程封装
模拟C++封装原生线程库pthread
版本一
#pragma once #include <iostream> #include <functional> #include <cstring> #include <cstdio> #include <pthread.h> using func_t = std::function<void()>; namespace quitesix { static int number = 1; class Thread { private: void EnableRunning() { _isrunning = true; } void EnableDetach() { _isdetach = true; } // 静态成员函数原因:非静态成员函数第一个参数是隐含的this指针,参数不匹配 static void *Routine(void *args) { Thread *self = static_cast<Thread *>(args); self->EnableRunning(); if(self->_isdetach) self->Detach(); // 设置名字 pthread_setname_np(self->_tid, self->_name.c_str()); // 回调 (self->_func)(); return nullptr; } public: Thread(func_t func) : _func(func) , _isdetach(false) , _isrunning(false) , _res(nullptr) { _name = "thread-" + std::to_string(number++); } ~Thread() { } bool Start() { if (_isrunning) return false; EnableRunning(); // 传递this指针,因为静态成员函数不存在this指针,需要访问this指针中_func进行回调 int n = pthread_create(&_tid, nullptr, Routine, this); if (n != 0) { std::cerr << "线程创建失败," << strerror(n) << std::endl; return false; } std::cout << "线程创建成功!" << std::endl; if (_isdetach) Detach(); return true; } void Stop() { if (_isrunning) { int n = pthread_cancel(_tid); if (n != 0) { std::cerr << "线程取消失败," << strerror(n) << std::endl; return; } std::cout << "线程取消成功" << std::endl; _isrunning = true; } } void Detach() { // 已经分离了,直接退 if (_isdetach) return; // 在运行且没有分离,分离 if (_isrunning) pthread_detach(_tid); EnableDetach(); std::cout << "线程分离成功" << std::endl; } void Join() { if (!_isrunning) return; int n = pthread_join(_tid, nullptr); if (n != 0) { std::cerr << "线程等待失败," << strerror(n) << std::endl; return; } std::cout << "线程等待成功" << std::endl; } private: pthread_t _tid; // 线程ID func_t _func; // 线程要执行的事务 bool _isdetach; // 是否分离 bool _isrunning; // 线程是否运行 std::string _name; // 线程名 void *_res; // 返回值 }; }注意:Routine函数设置的是静态成员函数,原因:静态成员函数参数第一个不包含隐式的this指针,为了符合pthread_create函数要求的 void *(*)(void *)类型。
Rountine函数中为了能访问类的成员变量,采用参数接受this指针的方式,pthread_create函数的参数传递this指针。
pthread_setname_np和pthread_getname_np可以用来设置线程的名字,用于debug。
版本二
若要实现线程事务可传参,可以用类模板的形式实现。
线程局部存储
语法:在类型前加__thread
线程局部存储作用:全局变量,我不想这个变量让其他线程看到
线程局部存储:只能存储内置类型和部分指针
更多推荐





所有评论(0)