std::thread是C++并发编程的基础,用于创建和管理线程,需手动调用join()或detach()管理生命周期,避免数据竞争应使用互斥量,传递引用需用std::ref,获取结果可结合std::promise与std::future,而C++20的std::jthread提供了自动管理线程生命周期的改进。

C++并发编程中,
std::thread
std::thread
使用
std::thread
要使用
std::thread
<thread>
1. 创建并启动线程
立即进入“豆包AI人工智官网入口”;
立即学习“豆包AI人工智能在线问答入口”;
最直接的方式是传递一个函数名或Lambda表达式给
std::thread
#include <iostream>
#include <thread>
#include <string>
#include <chrono> // 用于std::this_thread::sleep_for
// 普通函数作为线程入口
void worker_function(int id, const std::string& message) {
std::cout << "Thread " << id << ": " << message << " (Running on core "
<< std::this_thread::get_id() << ")" << std::endl;
// 模拟一些工作
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Thread " << id << " finished." << std::endl;
}
// 函数对象(Functor)作为线程入口
class FunctorWorker {
public:
void operator()(int id) {
std::cout << "Functor Thread " << id << " is running." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
std::cout << "Functor Thread " << id << " finished." << std::endl;
}
};
int main() {
std::cout << "Main thread started." << std::endl;
// 方式一:使用普通函数
// 传递给线程函数的参数,会在线程创建时被拷贝一份
std::thread t1(worker_function, 1, "Hello from function");
// 方式二:使用Lambda表达式
// Lambda捕获的变量也会被拷贝(如果不是引用捕获)
std::thread t2([](int id, const std::string& msg) {
std::cout << "Lambda Thread " << id << ": " << msg << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
std::cout << "Lambda Thread " << id << " finished." << std::endl;
}, 2, "Greetings from lambda");
// 方式三:使用函数对象(Functor)
FunctorWorker fw;
std::thread t3(fw, 3); // 注意:fw会被拷贝到线程对象内部
// 方式四:使用类的成员函数(需要对象实例和成员函数指针)
// 这种方式稍微复杂一些,需要将对象实例的指针或引用作为第一个参数传递
class MyClass {
public:
void member_func(int id) {
std::cout << "Member Function Thread " << id << " is running." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::cout << "Member Function Thread " << id << " finished." << std::endl;
}
};
MyClass obj;
std::thread t4(&MyClass::member_func, &obj, 4); // &obj 是对象实例的指针
// ... 线程管理 ...
// 务必在线程对象生命周期结束前调用 join() 或 detach()
// 否则,程序会在 std::thread 析构时调用 std::terminate 终止。
// 等待线程完成
t1.join(); // 主线程会阻塞,直到t1完成
t2.join(); // 主线程会阻塞,直到t2完成
t3.join(); // 主线程会阻塞,直到t3完成
t4.join(); // 主线程会阻塞,直到t4完成
std::cout << "Main thread finished. All threads joined." << std::endl;
return 0;
}2. 线程的管理:join()
detach()
这是
std::thread
std::thread
join()
detach()
std::terminate
join()
t.join();
t
join()
t
detach()
t.detach();
t
std::thread
std::thread
t
3. 线程参数传递
默认情况下,传递给线程函数的参数都是按值拷贝的。这意味着即使你的函数签名是按引用接收,传递给
std::thread
如果你确实想按引用传递参数,需要使用
std::ref
std::cref
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include <numeric> // for std::accumulate
#include <functional> // for std::ref
void accumulate_sum(const std::vector<int>& data, long long& result) {
result = std::accumulate(data.begin(), data.end(), 0LL);
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
long long sum_result = 0;
// 如果不使用 std::ref,sum_result 会被拷贝,线程修改的是拷贝,而不是外部的 sum_result
std::thread t(accumulate_sum, std::ref(numbers), std::ref(sum_result));
t.join();
std::cout << "Accumulated sum: " << sum_result << std::endl; // 输出 55
return 0;
}这里,
std::ref(numbers)
std::ref(sum_result)
accumulate_sum
main
numbers
sum_result
std::thread
在使用
std::thread
一个最直接的陷阱就是未处理的线程生命周期。前面提到了,如果一个
std::thread
std::terminate
join()
detach()
std::thread
join()
detach()
try-catch
finally
join()
另一个核心问题是数据竞争(Data Race)。当多个线程同时访问并修改同一个共享资源(比如一个全局变量、一个类的成员变量、一个
std::vector
++
std::mutex
std::lock_guard
std::unique_lock
#include <iostream>
#include <thread>
#include <mutex> // for std::mutex and std::lock_guard
#include <vector>
std::mutex mtx; // 全局互斥量
int shared_counter = 0;
void increment_counter() {
for (int i = 0; i < 10000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁,作用域结束自动解锁
shared_counter++;
}
}
int main() {
std::thread t1(increment_counter);
std::thread t2(increment_counter);
t1.join();
t2.join();
std::cout << "Final counter value: " << shared_counter << std::endl; // 期望是 20000
return 0;
}如果没有
std::lock_guard
shared_counter
此外,异常安全也是一个值得关注的点。如果一个线程函数在
join()
std::thread
std::terminate
std::promise
std::future
最后,性能考量。虽然多线程旨在提升性能,但线程的创建、销毁、上下文切换以及锁的开销都可能抵消其带来的好处。创建过多的线程,或者线程之间的竞争过于激烈,反而可能导致性能下降。所以,设计并发程序时,要合理分配任务,尽量减少共享状态,并选择合适的同步原语。
std::thread
安全地传递参数和获取结果是多线程编程中一个核心的挑战。如果你只是传递基本类型,通常不会有太多问题,因为它们会被拷贝。但当涉及引用、大对象、所有权转移或异步结果时,就需要更精细的策略。
1. 传递引用:使用 std::ref
std::cref
前面已经展示过,
std::thread
std::ref
std::cref
#include <iostream>
#include <thread>
#include <string>
#include <functional> // For std::ref
void modify_string(std::string& s) {
s += " (modified by thread)";
}
int main() {
std::string original_str = "Hello Thread";
std::cout << "Before thread: " << original_str << std::endl;
std::thread t(modify_string, std::ref(original_str));
t.join();
std::cout << "After thread: " << original_str << std::endl; // 输出修改后的字符串
return 0;
}2. 传递移动语义对象:使用 std::move
对于那些不支持拷贝但支持移动(Move-only types)的对象,例如
std::unique_ptr
std::thread
std::ofstream
std::move
#include <iostream>
#include <thread>
#include <memory> // For std::unique_ptr
void process_unique_ptr(std::unique_ptr<int> ptr) {
if (ptr) {
std::cout << "Thread received unique_ptr with value: " << *ptr << std::endl;
} else {
std::cout << "Thread received a null unique_ptr." << std::endl;
}
}
int main() {
auto my_ptr = std::make_unique<int>(42);
std::cout << "Main thread unique_ptr value: " << *my_ptr << std::endl;
// 将 my_ptr 的所有权转移给新线程
std::thread t(process_unique_ptr, std::move(my_ptr));
t.join();
// 此时 my_ptr 在主线程中已经失效,不再拥有资源
if (!my_ptr) {
std::cout << "Main thread's unique_ptr is now null." << std::endl;
}
return 0;
}3. 获取线程执行结果:std::promise
std::future
std::thread
std::promise
std::future
std::promise
std::future
std::promise
get()
#include <iostream>
#include <thread>
#include <future> // For std::promise and std::future
#include <numeric>
#include <vector>
void calculate_sum_async(std::promise<long long> p, const std::vector<int>& data) {
try {
long long sum = std::accumulate(data.begin(), data.end(), 0LL);
p.set_value(sum); // 设置结果
} catch (...) {
p.set_exception(std::current_exception()); // 捕获并传递异常
}
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::promise<long long> sum_promise;
std::future<long long> sum_future = sum_promise.get_future(); // 获取未来结果的句柄
std::thread t(calculate_sum_async, std::move(sum_promise), numbers); // 移动 promise
// 主线程可以做其他事情...
std::cout << "Main thread doing other work..." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// 等待并获取结果
try {
long long result = sum_future.get(); // get() 会阻塞直到结果可用
std::cout << "Async sum result: " << result << std::endl;
} catch (const std::exception& e) {
std::cerr << "Error in thread: " << e.what() << std::endl;
}
t.join();
return 0;
}这种模式非常优雅,它将结果的生产和消费解耦,允许主线程在等待结果的同时执行其他任务。
std::thread
std::async
std::jthread
C++标准库为我们提供了多种并发工具,
std::thread
std::async
std::jthread
1. std::thread
std::thread
join()
detach()
std::promise
std::future
**2
以上就是C++并发编程 thread基本使用方法的详细内容,更多请关注php中文网其它相关文章!
编程怎么学习?编程怎么入门?编程在哪学?编程怎么学才快?不用担心,这里为大家提供了编程速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号