Igo*_*r37 5 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();
}
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).