
假设有个类的两个成员函数,需要在不同的线程里执行,这两个成员函数需要写入同一个文件,因此需要使用 mutex 确保这两个函数不会同时写,代码类似这样
clss Widget{ public: void funA(); void funnB(); private: std::mutex mutex; }; void Widget::funA(){ { std::unique_lock(mutex); //operate A; } } void Widget::funB(){ { std::unique_lock(mutex); //operate B; } } 然后设计两个函数来封装这两个成员函数,类似
void execA(Widget* w){ w->funcA(); }; 最后程序里,生成一个 Widget 的对象,需要在两个线程里执行这两个函数,即
Widget* w{}; std::jthread threadA(execA, &w); //在一个线程里执行 A 函数 std::jthread threadB(execB, &w); //在另一个线程里执行 B 函数 在这种情况下,大多数式成员函数 funcA()先执行,但多次尝试后,有几次式 funcB()先获得 mutex 。
在下列三个前置条件下
我向问下,有没有办法确保 A 一定在 B 之前获得 mutex ?
1 LcDraven 2024-11-19 16:16:39 +08:00 用信号量控制两个线程的同步关系 |
2 billlee 2024-11-19 16:19:02 +08:00 你的需求是 threadB 在 threadA 后执行,这个不是 mutex 能解决的问题。请使用条件变量 |
3 LcDraven 2024-11-19 16:27:10 +08:00 @billlee 他的场景用条件变量不是把简单问题复杂化了吗?用信号量最优吧我觉得,或者再用一个互斥锁也可以同步线程的同步关系,甚至用全局变量加互斥锁也可以。但是信号量是最简单最专业的吧 |
4 GeruzoniAnsasu 2024-11-19 16:30:56 +08:00 https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange spinlock 的典型场景呗 B 线程读 flag, A 线程写 flag |
6 jujusama 2024-11-19 16:57:42 +08:00 在 Widget 的构造内将 mutex.lock(),在 function A 内使用 std::unique_lock(mutex, std::adopt_lock); |
7 A1st0n 2024-11-20 09:37:28 +08:00 使用条件变量: ``` #include <iostream> #include <mutex> #include <condition_variable> #include <thread> #include <chrono> class Widget { public: void funcA() { std::unique_lock lock(mutex_); std::cout << "funcA starts\n"; std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟操作 std::cout << "funcA ends\n"; // 标记 A 已完成,通知等待的线程 funcA_done_ = true; cv_.notify_one(); } void funcB() { // 等待 funcA 完成 std::unique_lock lock(cv_mutex_); cv_.wait(lock, [this] { return funcA_done_; }); std::unique_lock file_lock(mutex_); std::cout << "funcB starts\n"; std::this_thread::sleep_for(std::chrono::seconds(1)); // 模拟操作 std::cout << "funcB ends\n"; } private: std::mutex mutex_; // 用于文件操作的互斥锁 std::mutex cv_mutex_; // 用于条件变量的互斥锁 std::condition_variable cv_; // 条件变量 bool funcA_done_ = false; // 标志 funcA 是否已完成 }; // 封装函数 void execA(Widget* w) { w->funcA(); } void execB(Widget* w) { w->funcB(); } int main() { Widget w; // 使用 std::jthread std::jthread threadA(execA, &w); // 在一个线程里执行 A 函数 std::jthread threadB(execB, &w); // 在另一个线程里执行 B 函数 return 0; } ``` |