大致草稿——————————
思维导图
学习目标
一、线程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; // }