std::unique_lock <std::mutex> lck(mtx)
时间: 2023-12-08 22:31:31 浏览: 244
std::unique_lock<std::mutex> lck(mtx)是一个用于互斥量的RAII(Resource Acquisition Is Initialization)包装器。它具有以下特点:
- std::unique_lock可以在构造时选择是否立即锁定互斥量,而std::lock_guard在构造时会立即锁定互斥量。这使得std::unique_lock更加灵活,但同时也可能带来更多的开销。
- std::unique_lock支持同时锁定多个互斥量,这可以避免多个互斥量之间的死锁问题。当在使用std::condition_variable时,应该使用std::unique_lock而不是std::lock_guard。
- 与std::lock_guard不同的是,程序员可以手动解锁std::unique_lock,但不能手动解锁std::lock_guard。
相关问题
std::condition_variable配合std::unique_lock
`std::condition_variable`和`std::unique_lock`是C++11中提供的一种同步原语,它们通常一起用于实现条件变量,即当一个线程等待某个条件满足时进入睡眠状态,而其他线程通过改变条件可以唤醒它。
`std::condition_variable`负责维护一个“等待队列”,当线程调用`wait`或`wait_for`时,它会把自己放入这个队列,并进入睡眠状态。只有持有`std::unique_lock`的对象才能解锁并修改`condition_variable`的状态,从而唤醒等待的线程。
`std::unique_lock`则是一种独占锁,它既可以锁定也可以解锁某个互斥量(mutex)。当你需要等待某个条件时,你可以先锁定互斥量,然后创建一个`std::unique_lock`实例,并将其传递给`condition_variable`的`wait`方法。当条件满足时,释放互斥量(即调用`unlock`),这将唤醒等待的线程,然后继续执行。
示例代码片段:
```cpp
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
// 主线程设置条件
{
std::lock_guard<std::mutex> lck(mtx);
if (/* 条件满足 */) {
ready = true;
cv.notify_one(); // 唤醒等待者
}
}
// 等待线程
std::unique_lock<std::mutex> ulock(mtx);
cv.wait(ulock, [] { return ready; }); // 等待直到ready变为true
// 现在条件已满足,可以执行后续操作
```
using clock_type = std::chrono::system_clock; struct message { clock_type::time_point when; std::function<void()> callback; std::string param; }; class message_loop { public: message_loop(): _stop(false) { // } message_loop(const message_loop&) = delete; message_loop& operator=(const message_loop&) = delete; void run() { while (!_stop) { auto msg = wait_one(); msg.callback(); } } void quit() { post({clock_type::now(), this{ _stop = true; } }); } void post(std::function<void()> callable) { post({clock_type::now(), std::move(callable)}); } void post(std::function<void()> callable, std::chrono::milliseconds delay) { post({clock_type::now() + delay, std::move(callable)}); } private: struct msg_prio_comp { inline bool operator() (const message& a, const message& b) { return a.when > b.when; } }; using queue_type = std::priority_queue<message, std::vector<message>, msg_prio_comp>; std::mutex _mtx; std::condition_variable _cv; queue_type _msgs; bool _stop; void post(message msg) { auto lck = acquire_lock(); _msgs.emplace(std::move(msg)); _cv.notify_one(); } std::unique_lockstd::mutex acquire_lock() { return std::unique_lockstd::mutex(_mtx); } bool idle() const { return _msgs.empty(); } const message& top() const { return _msgs.top(); } message pop() { auto msg = top(); _msgs.pop(); return msg; } message wait_one() { while (true) { auto lck = acquire_lock(); if (idle()) _cv.wait(lck); else if (top().when <= clock_type::now()) return pop(); else { _cv.wait_until(lck, top().when); // 可能是新消息到达,再循环一次看看 } } } }; int main(int argc, char *argv[]) { using namespace std; using namespace std::chrono; message_loop *pLoop = new message_loop; thread th(pLoop{ pLoop->run(); }); cout << "POST 1"<<endl;; pLoop->post({ cout << "1"<<endl; }); cout << "POST 2"<<endl;; pLoop->post({ cout << "2"<<endl; }, milliseconds(500)); cout << "POST 3"<<endl;; pLoop->post({ cout << "3"<<endl; }); cout << "POST 4"<<endl;; pLoop->post({ cout << "4"<<endl; }, milliseconds(1000)); this_thread::sleep_for(milliseconds(1500)); // pLoop->quit(); cout << "Quit"<<endl; th.join(); cout << "here"<<endl; } 请优化一下,可以传参
可以将 message 结构体中的 param 字段用于传递参数,并相应地修改 post 函数和 wait_one 函数。具体代码如下:
```
using clock_type = std::chrono::system_clock;
struct message {
clock_type::time_point when;
std::function<void(const std::string&)> callback;
std::string param;
};
class message_loop {
public:
message_loop() : _stop(false) {}
message_loop(const message_loop&) = delete;
message_loop& operator=(const message_loop&) = delete;
void run() {
while (!_stop) {
auto msg = wait_one();
msg.callback(msg.param);
}
}
void quit() {
post({clock_type::now(), [](const std::string&) {}}, "");
_stop = true;
}
void post(std::function<void(const std::string&)> callable, const std::string& param) {
post({clock_type::now(), std::move(callable), param});
}
void post(std::function<void(const std::string&)> callable, std::chrono::milliseconds delay, const std::string& param) {
post({clock_type::now() + delay, std::move(callable), param});
}
private:
struct msg_prio_comp {
inline bool operator() (const message& a, const message& b) {
return a.when > b.when;
}
};
using queue_type = std::priority_queue<message, std::vector<message>, msg_prio_comp>;
std::mutex _mtx;
std::condition_variable _cv;
queue_type _msgs;
bool _stop;
void post(message msg) {
auto lck = acquire_lock();
_msgs.emplace(std::move(msg));
_cv.notify_one();
}
std::unique_lock<std::mutex> acquire_lock() {
return std::unique_lock<std::mutex>(_mtx);
}
bool idle() const {
return _msgs.empty();
}
const message& top() const {
return _msgs.top();
}
message pop() {
auto msg = top();
_msgs.pop();
return msg;
}
message wait_one() {
while (true) {
auto lck = acquire_lock();
if (idle()) {
_cv.wait(lck);
} else if (top().when <= clock_type::now()) {
auto msg = pop();
return msg;
} else {
_cv.wait_until(lck, top().when);
// 可能是新消息到达,再循环一次看看
}
}
}
};
int main(int argc, char *argv[]) {
using namespace std;
using namespace std::chrono;
message_loop *pLoop = new message_loop;
thread th(pLoop, &message_loop::run);
pLoop->post([](const std::string& param) { cout << "1 " << param << endl; }, "hello");
pLoop->post([](const std::string& param) { cout << "2 " << param << endl; }, milliseconds(500), "world");
pLoop->post([](const std::string& param) { cout << "3 " << param << endl; }, "foo");
pLoop->post([](const std::string& param) { cout << "4 " << param << endl; }, milliseconds(1000), "bar");
this_thread::sleep_for(milliseconds(1500));
pLoop->quit();
th.join();
}
```
阅读全文