std :: lock_guard有什么问题

Igo*_*r37 5 c++ multithreading c++11

我有简单的代码:第一线推std::stringsstd::list,及第二线程弹出std::stringsstd::list.所有std::list的操作都受到保护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();
}
Run Code Online (Sandbox Code Playgroud)

Wer*_*nze 20

您没有遵守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));
}
Run Code Online (Sandbox Code Playgroud)

您只是创建一个std::lock_guard立即创建和销毁的临时对象.您需要将对象命名为

{
    std::lock_guard<std::mutex> lg{ m };
    lst.push_back(std::to_string(i));
}
Run Code Online (Sandbox Code Playgroud)

这样锁定保护器就会一直存在,直到阻止结束.

正如您已经认识到的那样(CppCoreGuidelines):

使用RAII锁定保护(lock_guard,unique_lock,shared_lock),永远不要直接调用mutex.lock和mutex.unlock(RAII)

如果您使用的是Microsoft Visual Studio,我建议您使用代码分析并至少激活Microsoft本地推荐规则.如果这样做,您将收到编译器分析警告.

警告C26441:必须命名Guard对象(cp.44).

  • [不幸的是,这是一个很容易犯的错误.](/sf/answers/1133295971/) (3认同)
  • @Deduplicator我质疑它的实用性是多么有用,只是因为你可以将所有内容放在一行上,同时具有不寻常的语法并且如果你想要锁定其他东西需要重写(可以忘记并让你立即死锁如在OP中,对版本控制差异等是不利的.). (3认同)