Нужно ли блокировать?

Я встретил вопрос в 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 раз (и, вероятно, будет), но когда вещи действительно происходят одновременно (потому что вы позволяете это) - бум - Неопределенное поведение

Другие вопросы по тегам