Что не так с std :: lock_guard - PullRequest
       1

Что не так с std :: lock_guard

0 голосов
/ 31 декабря 2018

У меня есть простой код: первый поток выталкивает std::strings в std::list, а второй поток выталкивает std::strings из этого std::list.Все операции std::list s защищены с помощью std::mutex m.Этот код постоянно выводит на консоль сообщение об ошибке: "Error: lst.begin() == lst.end()".

Если я заменим std::lock_guard на конструкцию m.lock() и m.unlock(), код начнет работать правильно.Что не так с std::lock_guard?

#include <iostream>
#include <thread>
#include <mutex>
#include <list>
#include <string>

std::mutex m;
std::list<std::string> lst;

void f2()
{
    for (int i = 0; i < 5000; ++i)
    {
        std::lock_guard<std::mutex> { m };
        lst.push_back(std::to_string(i));
    }

    m.lock();
    lst.push_back("-1"); // last list's element
    m.unlock();
}

void f1()
{
    std::string str;

    while (true)
    {
        m.lock();
        if (!lst.empty())
        {
            if (lst.begin() == lst.end())
            {
                std::cerr << "Error: lst.begin() == lst.end()" << std::endl;
            }
            str = lst.front();
            lst.pop_front();
            m.unlock();
            if (str == "-1")
            {
                break;
            }
        }
        else
        {
            m.unlock();
            std::this_thread::yield();
        }
    }
}

// tested in MSVS2017
int main()
{
    std::thread tf2{ f2 };
    f1();
    tf2.join();
}

1 Ответ

0 голосов
/ 31 декабря 2018

Вы не подчинялись CppCoreGuidelines CP.44: Не забудьте назвать ваши lock_guards и unique_locks :).

В

for (int i = 0; i < 5000; ++i)
{
    std::lock_guard<std::mutex> { m };
    lst.push_back(std::to_string(i));
}

вы создаете только временныйstd::lock_guard объект, который создается и уничтожается немедленно.Вам нужно присвоить объекту имя, как в

{
    std::lock_guard<std::mutex> lg{ m };
    lst.push_back(std::to_string(i));
}

, чтобы защита блокировки сохранялась до конца блока.

И как вы уже узнали ( CppCoreGuidelines ):

Использовать средства защиты RAII (lock_guard, unique_lock, shared_lock), никогда не вызывать mutex.lock и mutex.unlock напрямую (RAII)

Если вы используете Microsoft VisualStudio, я рекомендую использовать анализ кода и активировать хотя бы Microsoft Native Recommended Rules .Если вы сделаете это, вы получите предупреждение анализа компилятора.

предупреждение C26441: Объекты охраны должны быть названы (cp.44).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...