创建线程

C++ 使用 std::thread 创建线程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <thread>

void task() {
std::cout << "子线程执行" << std::endl;
}

int main() {
std::thread t(task);

t.join();

return 0;
}

join

join() 表示等待子线程执行结束。

1
2
std::thread t(task);
t.join();

如果主线程不等待子线程,程序可能提前结束。

detach

detach() 表示让线程在后台独立运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <thread>
#include <chrono>

void task() {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "后台线程执行完成" << std::endl;
}

int main() {
std::thread t(task);

t.detach();

std::cout << "主线程结束" << std::endl;

std::this_thread::sleep_for(std::chrono::seconds(2));

return 0;
}

注意:

detach() 后线程不再受当前 std::thread 对象管理。

使用时要特别注意:

  • 不要访问已经销毁的局部变量
  • 不要依赖主线程生命周期
  • 不容易控制线程退出

joinable

joinable() 用于判断线程是否还可以被 join()detach()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <thread>

void task() {
std::cout << "任务执行" << std::endl;
}

int main() {
std::thread t(task);

if (t.joinable()) {
t.join();
}

return 0;
}

如果一个 std::thread 对象析构时仍然是 joinable 状态,程序会调用 std::terminate()

所以必须保证线程对象析构前已经:

  • join()
  • detach()

向线程传递参数

值传递

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <thread>

void print(int x) {
std::cout << "x = " << x << std::endl;
}

int main() {
std::thread t(print, 10);
t.join();

return 0;
}

引用传递

如果要传引用,需要使用 std::ref

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <thread>
#include <functional>

void add(int& x) {
x += 10;
}

int main() {
int value = 5;

std::thread t(add, std::ref(value));
t.join();

std::cout << value << std::endl;

return 0;
}

输出:

1
15

线程中的 lambda

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <thread>

int main() {
int x = 10;

std::thread t([x] {
std::cout << "x = " << x << std::endl;
});

t.join();

return 0;
}

如果使用引用捕获:

1
2
3
std::thread t([&x] {
x += 1;
});

要确保变量 x 在线程结束前仍然有效。

获取线程 ID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <thread>

void task() {
std::cout << "子线程 ID: "
<< std::this_thread::get_id()
<< std::endl;
}

int main() {
std::thread t(task);

std::cout << "主线程 ID: "
<< std::this_thread::get_id()
<< std::endl;

t.join();

return 0;
}

获取硬件并发数

1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <thread>

int main() {
unsigned int n = std::thread::hardware_concurrency();

std::cout << "硬件支持的并发线程数: " << n << std::endl;

return 0;
}

注意:

hardware_concurrency() 返回的是一个提示值,不保证一定准确。

线程休眠与让出 CPU

sleep_for

让当前线程休眠指定时间。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <thread>
#include <chrono>

int main() {
std::cout << "开始" << std::endl;

std::this_thread::sleep_for(std::chrono::seconds(1));

std::cout << "1 秒后继续执行" << std::endl;

return 0;
}

yield

主动让出 CPU,让调度器选择其他线程执行。

1
2
3
#include <thread>

std::this_thread::yield();

RAII 线程封装

为了避免忘记 join(),可以封装一个自动 join 的线程类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <thread>
#include <iostream>

class JoiningThread {
private:
std::thread t;

public:
explicit JoiningThread(std::thread thread)
: t(std::move(thread)) {}

~JoiningThread() {
if (t.joinable()) {
t.join();
}
}

JoiningThread(const JoiningThread&) = delete;
JoiningThread& operator=(const JoiningThread&) = delete;

JoiningThread(JoiningThread&&) = default;
JoiningThread& operator=(JoiningThread&&) = default;
};

void task() {
std::cout << "任务执行" << std::endl;
}

int main() {
JoiningThread jt(std::thread(task));

return 0;
}

C++20 中可以使用 std::jthread,析构时会自动 join。