c++ - std::lock_guard 有什么问题

标签 c++ multithreading c++11

我有简单的代码:第一个线程将 std::strings 推送到 std::list,第二个线程弹出 std::strings 从这个 std::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();
}

最佳答案

你没有服从CppCoreGuidelines CP.44: Remember to name your lock_guards and 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));
}

这样锁守卫就会一直存在到 block 的末尾。

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

Use RAII lock guards (lock_guard, unique_lock, shared_lock), never call mutex.lock and mutex.unlock directly (RAII)

如果您使用的是 Microsoft Visual Studio,我建议您使用代码分析并至少激活 Microsoft Native Recommended Rules。如果这样做,您将收到编译器分析警告。

warning C26441: Guard objects must be named (cp.44).

关于c++ - std::lock_guard 有什么问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53986760/

相关文章:

c++ - 查找僵尸线程的来源

c++ - std::hash 专门化我自己的类并在类中使用它

c++ - Visual C++ 6.0 中查找源文件的预设位置

C++ lambda 表达式(匿名函数)

c++ - 不同平台的系统异常处理

python - 使用 Pyramid 和 rq 写入同一个日志文件

c++ - 将 char 数组转换为 int 数组

java - 并行化此Java代码的最佳方法

c++ - boost 序列化 - 序列化 std::tr1::shared_ptr?

c++11 - 在给定 GLIBCXX 版本的情况下,如何找到已实现的 C++11 功能