Нужно ли блокировать?
Я встретил вопрос в Leetcode. Я рассмотрел некоторые решения в обсуждении. Но мое решение отличается от других, потому что я не использую lock
в методе first
, Интересно, правильный ли мой код? Кроме того, можете ли вы дать мне несколько советов о моем коде?
Я думаю, что нет необходимости использовать unique_lock
в методе void first(function<void()> printFirst)
любить void second(function<void()> printSecond)
, это правильно?
class Foo {
public:
Foo() {
}
void first(function<void()> printFirst) {
// cout<<1<<endl;
// printFirst() outputs "first". Do not change or remove this line.
// mtx.lock();
printFirst();
flag=1;
// mtx.unlock();
cond.notify_all();
// cout<<11<<endl;
}
void second(function<void()> printSecond) {
// cout<<2<<endl;
{
unique_lock<mutex> lk(mtx);
cond.wait(lk,[this](){return flag==1;});
// printSecond() outputs "second". Do not change or remove this line.
printSecond();
flag=2;
}
// cout<<22<<endl;
cond.notify_all();
}
void third(function<void()> printThird) {
// cout<<3<<endl;
unique_lock<mutex> lk(mtx);
cond.wait(lk,[this](){return flag==2;});
// printThird() outputs "third". Do not change or remove this line.
printThird();
flag=3;
// cout<<33<<endl;
}
mutex mtx;
condition_variable cond;
int flag=0;
};
3 ответа
Очевидно, что ваши трехэлементные функции должны вызываться разными потоками. Таким образом, вам нужно заблокировать мьютекс в каждом потоке, чтобы защитить общую переменную flag
от одновременного доступа. Так что вы должны раскомментировать mtx.lock()
а также mtx.unlock()
в first
чтобы защитить его там же. функции second
а также third
применить unique_lock
в качестве альтернативы для этого.
Обязательно разблокируйте мьютекс перед вызовом cond.notify_all()
либо по телефону mtx.unlock()
до или делая unique_lock
локальная переменная внутреннего блока кода, как в second
,
Дальнейший совет
Положить private:
перед переменными элемента в нижней части определения вашего класса, чтобы защитить их от внешнего доступа. Это будет гарантировать, что flag
не может быть изменено без блокировки мьютекса.
Это необходимо.
То, что ваш код выдал правильный вывод в этом случае, не имеет значения. Вполне возможно, что printFirst
может быть не завершено к тому времениprintSecond
называется. Вам нужен мьютекс, чтобы предотвратить это и остановить printSecond
а также printThird
, от того, чтобы бежать в то же время.
flag
проверка состояния в second()
или же third()
может оцениваться одновременно с first()
правопреемники 1
в flag
,
Перепишите это
cond.wait(lk, [this](){return flag==1;});
как это, и это может быть легче увидеть:
while(!(flag==1)) cond.wait(lk);
Он делает то же самое, что и ваш wait()
с лямбдой.
flag
должен быть прочитан, пока мьютекс удерживается - но first
не заботится о мьютексах и присваивает flag
когда угодно. Для неатомарных типов это катастрофа. Это может работать 10000000 раз (и, вероятно, будет), но когда вещи действительно происходят одновременно (потому что вы позволяете это) - бум - Неопределенное поведение