std::thread
是C++11中引入的一个多线程库,允许程序员在其应用程序中创建和管理线程。线程是一个独立执行的代码路径,能够与其他线程同时运行。通过使用std::thread
,程序可以更高效地利用现代多核处理器的能力。
要创建一个线程,最简单的方法是实例化一个std::thread
对象并传递一个可调用对象(函数、lambda表达式、函数对象等)给它。例如:
#include <iostream>
#include <thread>
void hello() {
std::cout << "Hello from a thread!" << std::endl;
}
int main() {
std::thread t(hello);
t.join(); // 等待线程t完成
return 0;
}
在这个例子中,hello
函数将在一个独立的线程中执行。t.join()
被调用以确保主线程等待新的线程完成。这是线程管理中一个重要的部分,因为如果主线程在子线程完成之前退出,会导致未定义的行为。
线程的生命周期始于std::thread
对象的创建,并在调用可调用对象完成时结束。线程可以通过两种方式与其父线程同步:
join
:阻塞调用线程直到线程对象完成。detach
:将线程与std::thread
对象分离,允许线程在后台独立运行。线程被分离后,将无法被join
,因此这种方式适用于线程独立于主线程且不需要返回结果或产生副作用。
除了普通函数,还可以使用lambda表达式和函数对象作为可调用对象。例如:
#include <iostream>
#include <thread>
int main() {
std::thread t([]() {
std::cout << "Hello from lambda expression" << std::endl;
});
t.join();
return 0;
}
在多线程环境中,一个常见的问题是多个线程同时访问共享资源时导致数据竞争。C++标准库提供了多种机制来处理这些问题,如互斥锁(std::mutex
)和条件变量(std::condition_variable
)。
互斥锁用于确保同一时间只有一个线程可以访问特定的代码区域:
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_safe(const std::string& msg) {
std::lock_guard<std::mutex> lock(mtx);
std::cout << msg << std::endl;
}
int main() {
std::thread t1(print_safe, "Hello from thread 1");
std::thread t2(print_safe, "Hello from thread 2");
t1.join();
t2.join();
return 0;
}
在这个例子中,std::mutex
保证了print_safe
函数在任何时候只有一个线程能够执行,避免竞争条件。
条件变量允许线程等待某个条件发生变化,再继续执行。这在需要线程之间协调操作时非常有用:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void print_id(int id) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return ready; });
std::cout << "Thread " << id << std::endl;
}
void go() {
std::unique_lock<std::mutex> lock(mtx);
ready = true;
cv.notify_all();
}
int main() {
std::thread threads[10];
for (int i = 0; i < 10; ++i) {
threads[i] = std::thread(print_id, i);
}
std::cout << "10 threads ready to race..." << std::endl;
go();
for (auto& th : threads) {
th.join();
}
return 0;
}
在这个程序中,10个线程会在cv.wait
处等待,直到go
函数设置ready
为true
并通知所有等待的线程。
C++标准库不直接支持线程的硬件亲和性设置,但操作系统通常提供了相关的API。如在Linux系统中,通过pthread
库可以实现,这涉及到高级主题,通常需要经验和具体的应用场景来细致考虑。
std::lock
或std::scoped_lock
这样的工具,能够降低死锁出现的概率。C++的std::thread
提供了创建和管理多线程应用的基本工具。但是,进入多线程编程世界需要对并发、同步以及可能出现的问题有很好的理解,并且在代码结构设计上也需要相应地周密考虑。这是一个复杂但非常强大的编程领域,旨在提升程序在多核处理器上的性能,而正确地实现并不要止步于语法学习,更重要的是在实践中总结经验。