假设有个类的两个成员函数,需要在不同的线程里执行,这两个成员函数需要写入同一个文件,因此需要使用 mutex 确保这两个函数不会同时写,代码类似这样
class 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 4 天前
用信号量控制两个线程的同步关系
|
2
billlee 4 天前
你的需求是 threadB 在 threadA 后执行,这个不是 mutex 能解决的问题。请使用条件变量
|
3
LcDraven 4 天前
@billlee 他的场景用条件变量不是把简单问题复杂化了吗?用信号量最优吧我觉得,或者再用一个互斥锁也可以同步线程的同步关系,甚至用全局变量加互斥锁也可以。但是信号量是最简单最专业的吧
|
4
GeruzoniAnsasu 4 天前
https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange
spinlock 的典型场景呗 B 线程读 flag, A 线程写 flag |
6
jujusama 4 天前
在 Widget 的构造内将 mutex.lock(),在 function A 内使用 std::unique_lock(mutex, std::adopt_lock);
|
7
A1st0n 3 天前
使用条件变量:
``` #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; } ``` |