参考引用
- C++11 14 17 20 多线程从原理到线程池实战
- 代码运行环境:Visual Studio 2019
#include
#include
using namespace std;
// 创建的子线程的入口函数
void ThreadMain() {
// 获取子线程开始时刻的 ID 号
cout << "begin sub thread ID " << this_thread::get_id() << endl;
for (int i = 0; i < 5; i++) {
cout << "in thread " << i << endl;
// 子线程睡眠(释放)CPU 资源 1000ms
this_thread::sleep_for(chrono::seconds(1));
}
cout << "end sub thread ID " << this_thread::get_id() << endl;
}
// 主线程的入口函数 main()
int main(int argc, char* argv[]) {
cout << "main thread ID " << this_thread::get_id() << endl;
// 线程创建启动
thread th(ThreadMain);
cout << "begin wait sub thread" << endl;
// 阻塞等待子线程退出
th.join();
cout << "end wait sub thread" << endl;
return 0;
}
main thread ID 21580
begin wait sub thread
begin sub thread ID 22924
in thread 0
in thread 1
in thread 2
in thread 3
in thread 4
end sub thread ID 22924
end wait sub thread
thread_detach.cpp
#include
#include
using namespace std;
bool is_exit = false;
void ThreadMain() {
cout << "begin sub thread ID " << this_thread::get_id() << endl;
for (int i = 0; i < 5; i++) {
if (!is_exit)
break;
cout << "in thread " << i << endl;
this_thread::sleep_for(chrono::seconds(1)); // 子线程睡眠(释放)CPU 资源 1000ms
}
cout << "end sub thread ID " << this_thread::get_id() << endl;
}
int main(int argc, char* argv[]) {
{
//thread th(ThreadMain); // 出错,thread 对象被销毁 子线程还在运行
}
{
thread th(ThreadMain);
th.detach(); // 子线程与主线程分离 守护线程(在后台运行)
// 但存在一个问题:主线程退出后 子线程不一定退出
}
{
thread th(ThreadMain);
this_thread::sleep_for(chrono::seconds(1));//1000ms
is_exit = true; // 通知子线程退出
cout << "主线程阻塞,等待子线程退出" << endl;
th.join(); // 主线程阻塞,等待子线程退出
cout << "子线程已经退出!" << endl;
}
getchar();
return 0;
}
控制台输出
begin sub thread ID 25520
end sub thread ID 25520
begin sub thread ID 23324
end sub thread ID 23324
主线程阻塞,等待子线程退出
子线程已经退出!
thread_para.cpp
#include
#include
#include
using namespace std;
class Para {
public:
Para() {
cout << "Create Para" << endl;
}
Para(const Para& p) { // 拷贝构造函数
cout << "Copy Para" << endl;
}
~Para() {
cout << "Drop Para" << endl;
}
string name;
};
void ThreadMain(int p1, float p2, string str, Para p4) {
this_thread::sleep_for(100ms);
cout << "ThreadMain " << p1 << " " << p2 << " " << str << " " << p4.name << endl;
}
int main(int argc, char* argv[]) {
thread th;
{
float f1 = 12.1f;
Para p;
p.name = "test Para class";
// 所有的参数做复制
th = thread(ThreadMain, 101, f1, "test string para", p);
}
th.join();
return 0;
}
控制台输出
Create Para
Copy Para
Drop Para
Copy Para
ThreadMain 101 12.1 test string para
Drop Para
Drop Para
参数传递存在的问题
thread_para.cpp
#include
#include
#include
using namespace std;
class Para {
public:
Para() { cout << "Create Para" << endl; }
Para(const Para& p) { cout << "Copy Para" << endl; }
~Para() { cout << "Drop Para" << endl; }
string name;
};
void ThreadMain(int p1, float p2, string str, Para p4) {
this_thread::sleep_for(100ms);
cout << "ThreadMain " << p1 << " " << p2 << " " << str <<" "<<p4.name<< endl;
}
void ThreadMainPtr(Para* p) {
this_thread::sleep_for(100ms);
cout << "ThreadMainPtr name = " << p->name << endl;
}
void ThreadMainRef(Para& p) {
this_thread::sleep_for(100ms);
cout << "ThreadMainPtr name = " << p.name << endl;
}
int main(int argc, char* argv[]) {
{
// 传递引用
Para p;
p.name = "test ref";
thread th(ThreadMainRef, ref(p));
th.join();
}
getchar();
{
// 传递线程指针
Para p;
p.name = "test ThreadMainPtr name";
thread th(ThreadMainPtr, &p);
th.detach(); // 错误,线程访问的 p 空间会提前释放
}
getchar(); // Para 释放
{
// 传递线程指针
Para p;
p.name = "test ThreadMainPtr name";
thread th(ThreadMainPtr, &p);
th.join();
getchar();
}
thread th;
{
float f1 = 12.1f;
Para p;
p.name = "test Para class";
// 所有的参数做复制
th = thread(ThreadMain, 101, f1, "test string para", p);
}
th.join();
return 0;
}
Create Para
ThreadMainPtr name = test ref
Drop Para
XThread.h
#pragma once
#include
#include
class XThread {
public:
virtual void Start() {
is_exit_ = false;
th_ = std::thread(&XThread::Main, this);
}
virtual void Stop() {
is_exit_ = true;
Wait();
}
virtual void Wait() {
if (th_.joinable())
th_.join();
}
bool is_exit() {
return is_exit_;
}
private:
virtual void Main() = 0; // 纯虚函数必须要在基类中实现
std::thread th_;
bool is_exit_ = false; // 符合谷歌代码风格,私有成员变量后缀加 _
};
thread_class.cpp
#include
#include
#include
#include "XThread.h"
using namespace std;
/*
class MyThread {
public:
// 入口线程函数
void Main() {
cout << "MyThread Main" << name << ": " << age;
}
string name;
int age = 0;
};
*/
class TestXThread : public XThread {
public:
void Main() override {
cout << "TestXThread Main begin" << endl;
while (!is_exit()) {
this_thread::sleep_for(100ms);
cout << "." << flush; // 添加 flush 是为了确保 . 正常输出
}
cout << "\nTestXThread Main end" << endl;
}
string name;
};
int main(int argc, char* argv[]) {
TestXThread testth;
testth.name = "TestXThread name ";
testth.Start();
this_thread::sleep_for(3s);
testth.Stop();
testth.Wait();
getchar();
/*
MyThread myth;
myth.name = "Test name";
myth.age = 20;
thread th(&MyThread::Main, &myth);
th.join();
*/
return 0;
}
控制台输出
TestXThread Main begin
............................
TestXThread Main end
lambda 函数基本格式
thread_lambda.cpp
#include
#include
#include
using namespace std;
class TestLambda {
public:
void Start() {
thread th([this]() {cout << "name = " << name << endl; });
th.join();
}
string name = "Test Lambda";
};
int main(int argc, char* argv[]) {
thread th(
[](int i) {cout << "test lambda " << i << endl;},
123
);
th.join();
TestLambda test;
test.Start();
return 0;
}
控制台输出
test lambda 123
name = Test Lambda
初始化函数可以在每一个类型的构造里都调用一遍,不用明确区分,代码可读性提升
call_once.cpp
#include
#include
#include
#include
using namespace std;
void SystemInit() {
cout << "Call SystemInit" << endl;
}
void CallOnceSystemInit() {
static std::once_flag flag; // 通过 flag 区分是否只调用一次
std::call_once(flag, SystemInit);
}
int main(int argc, char* argv[]) {
CallOnceSystemInit();
CallOnceSystemInit();
for (int i = 0; i < 3; i++) {
thread th(CallOnceSystemInit);
th.detach();
}
getchar();
return 0;
}
控制台输出
Call SystemInit