大致草稿——————————
思維導圖
學習目標
一、線程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;
// }