C++11学习之多线程的支持详解
在C++11标准中,多线程支持成为了一个正式的标准库,并引入了一些新的概念和类型,如线程、互斥锁、条件变量等,以及一些用于控制线程行为的函数和类。
下面我们来详细讲解多线程的支持。
线程
在线程头文件<thread>
中定义了线程类std::thread
,用于创建和控制线程。线程类的构造函数接收一个可调用对象,并执行它。例如,下面的代码创建了一个线程,并使用lambda函数作为可调用对象:
#include <iostream>
#include <thread>
void foo() {
std::cout << "Hello, World!" << std::endl;
}
int main() {
std::thread t(foo);
t.join(); // 等待线程 t 执行完毕
return 0;
}
上面的代码中,std::thread t(foo)
创建一个新的线程,并执行 foo()
函数。线程执行完毕后,必须调用join()
函数才能等待并回收线程资源。
线程类还提供了一些其他的创建线程的方式,如:
std::thread t1;
t1 = std::thread(foo); // 拷贝构造函数
std::thread t2(foo); // 直接构造函数
std::thread t3(&foo); // 函数指针作为可调用对象
std::thread t4([]{ foo(); }); // lambda函数作为可调用对象
互斥锁
互斥锁是用于控制对共享资源的访问的一种机制。在C++11标准中,定义了std::mutex
类型,用于实现互斥锁。
互斥锁的使用分为两个步骤:上锁和解锁。当一个线程对共享资源进行访问时,需要先上锁,以防止其他线程同时对同一共享资源进行操作。操作结束后,需要解锁以释放互斥锁,使得其他线程可以对共享资源进行操作。
#include <iostream>
#include <thread>
#include <mutex>
int counter = 0;
std::mutex mtx;
void increment() {
for (int i = 0; i < 10000; ++i) {
std::lock_guard<std::mutex> lock(mtx);
++counter;
}
}
int main() {
// 创建两个线程对counter进行操作
std::thread t1(increment);
std::thread t2(increment);
// 等待两个线程执行完毕
t1.join();
t2.join();
std::cout << "Counter = " << counter << std::endl;
return 0;
}
上面的代码中,我们使用互斥锁保证了counter变量的线程安全。在increment()
函数中,我们使用了std::lock_guard<std::mutex>
类,它会自动在构造函数中上锁,在析构函数中解锁。
注意:当调用的函数可能抛出异常时,需要使用std::unique_lock
类手动上锁和解锁。
条件变量
条件变量是一种用于线程间通信的机制。在C++11标准中,条件变量有std::condition_variable
和std::condition_variable_any
两种类型。
我们使用条件变量来实现一个生产者消费者模型:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
std::queue<int> q;
std::mutex mtx;
std::condition_variable cv;
void producer() {
for (int i = 0; i < 10; i++) {
std::unique_lock<std::mutex> lock(mtx);
q.push(i);
lock.unlock();
cv.notify_one();
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟生产者生产速度
}
}
void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !q.empty(); });
auto item = q.front();
q.pop();
lock.unlock();
std::cout << "Consumer " << std::this_thread::get_id() << " consumed " << item << std::endl;
}
}
int main() {
std::thread producer_thread(producer);
std::thread consumer_thread(consumer);
consumer_thread.join();
producer_thread.join();
return 0;
}
上面的代码中,生产者线程和消费者线程共享队列q,并且使用互斥锁和条件变量来保证线程安全和正确的顺序。
生产者线程在生产一个item之后,将其压入队列q,并通过cv.notify_one()
通知消费者线程可以消费了,然后等待一段时间继续生产。消费者线程在等待队列不为空时,从队列头部取出一个item,输出它,并继续等待下一个item。
总结
本文讲解了C++11标准中多线程的支持,涉及线程、互斥锁、条件变量等多个方面。对于初学者来说,理解这些概念并熟练掌握它们的使用可以使你写出更安全、更高效、更复杂的多线程程序。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++11学习之多线程的支持详解 - Python技术站