std::scoped_lock和
std::lock() 同时锁多个mutex
std::scoped_lock
和 std::lock()
都是 C++ 标准库中用于管理多个 std::mutex
对象的工具,但它们在使用方式和一些方面上存在一些区别。以下是它们的主要区别:
-
用法差异:
std::scoped_lock
是一个模板类,你需要将要锁定的所有std::mutex
作为参数传递给它的构造函数。它会在构造时锁定所有提供的互斥量,而在析构时自动释放这些锁。
std::mutex mtx1; std::mutex mtx2;{std::scoped_lock lock(mtx1, mtx2); // 锁定 mtx1 和 mtx2// 在这个作用域内,mtx1 和 mtx2 都已经被成功锁定 } // 在这个作用域结束时,mtx1 和 mtx2 会被解锁支持RAII
std::lock()
是一个函数,接受任意数量的std::mutex
参数,并在一次函数调用中尽可能地同时锁定所有提供的互斥量。这可以避免死锁,并且比分别调用std::lock_guard
或std::unique_lock
更高效。
std::mutex mtx1; std::mutex mtx2;std::lock(mtx1, mtx2); // 锁定 mtx1 和 mtx2 //需要手动解锁,不支持RAII
-
死锁避免:
std::lock()
在一次函数调用中尝试锁定所有提供的互斥量,如果无法同时锁定,会产生std::system_error
异常。因此,在使用std::lock
时,确保所有互斥量都是可锁定的,否则会导致程序异常终止。std::scoped_lock
在构造时就锁定了所有提供的互斥量,如果无法同时锁定会产生std::system_error
异常。因此,在使用std::lock
时,确保所有互斥量都是可锁定的,否则会导致程序异常终止。
在C++中,条件变量(Condition Variable)是用于线程间同步的一种机制。条件变量通常与互斥锁结合使用,用于实现线程的等待和唤醒机制,以确保线程在满足某些条件时才能执行。
常用的条件变量相关的类有 std::condition_variable
和 std::condition_variable_any
。以下是简要介绍和使用条件变量的基本模式:
条件变量
std::condition_variable
使用示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>std::mutex mtx;
std::condition_variable cv;
bool dataReady = false;void producer() {// 模拟生产数据std::this_thread::sleep_for(std::chrono::seconds(2));// 加锁,修改共享状态std::unique_lock<std::mutex> lock(mtx);dataReady = true;// 通知等待的线程cv.notify_one();
}void consumer() {std::unique_lock<std::mutex> lock(mtx);// 等待条件变量通知cv.wait(lock, [] { return dataReady; });// 消费数据std::cout << "Data consumed." << std::endl;
}int main() {std::thread producerThread(producer);std::thread consumerThread(consumer);producerThread.join();consumerThread.join();return 0;
}
在这个示例中,std::condition_variable
与 std::mutex
一起使用,cv.wait(lock, predicate)
用于等待条件变量的通知,而 cv.notify_one()
用于通知等待的线程。
要点:
std::condition_variable
需要与std::mutex
一起使用,以确保在条件变量上进行操作时的线程安全性。std::unique_lock
提供了更灵活的锁定和解锁操作,可以在需要的时候手动解锁,例如在等待条件变量时。cv.wait(lock, predicate)
中的predicate
是一个可选的谓词函数,用于检查条件是否满足,如果条件不满足,则继续等待。
条件变量的正确使用可以确保线程在适当的时候等待和唤醒,以避免不必要的轮询和提高程序的效率。
线程异步和通信
std::promise异步调用
std::promise
和 std::future
是 C++11 标准库中提供的两个工具,用于在多线程之间传递数据或者实现异步操作。
-
std::promise:
-
std::promise
用于在一个线程中存储一个值,然后在另一个线程中通过std::future
获取这个值。一个std::promise
对象关联一个std::future
对象,后者可以在其他线程中被用来获取由std::promise
对象设置的值。 -
std::promise
的set_value
成员函数只能成功调用一次。一旦调用set_value
,std::promise
对象就变得不能再用于设置新的值。 -
std::future 提供访问异步操作结果的机制 get() 阻塞等待promise set_value 的值
-
示例:
#include <iostream> #include <future>void setValue(std::promise<int>& prom) {prom.set_value(42); }int main() {std::promise<int> myPromise;std::future<int> myFuture = myPromise.get_future();std::thread t(setValue, std::ref(myPromise));t.join();int result = myFuture.get();std::cout << "Received value from promise: " << result << std::endl;return 0; }
std::promise
用于在一个线程中设置值,然后通过与关联的std::future
在另一个线程中获取这个值。std::future
则用于获取异步任务的结果。 -
-
std::future:
-
std::future
用于从异步任务中获取值。std::future
对象可以通过与std::promise
关联,或者通过std::async
、std::packaged_task
等方式创建。 -
示例:
#include <iostream> #include <future>int calculate() {return 21; }int main() {std::future<int> myFuture = std::async(std::launch::async, calculate);int result = myFuture.get();std::cout << "Result from future: " << result << std::endl;return 0; }
-
需要注意的是,std::promise
和 std::future
通常是成对使用的,但也可以通过其他方式创建 std::future
对象,比如使用 std::async
。
总体来说,std::promise
和 std::future
是 C++ 中实现简单异步编程的一种方便机制。