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