std::lock_guard导致未定义的行为
std::lock_guard causing undefined behavior
编辑:正如下面的评论所指出的,问题似乎不是我实际上创建了lock_guard的本地实例,而是一个匿名的临时实例,它立即被再次销毁。
Edit2:启用clang的线程清理程序有助于在运行时查明这些类型的问题。可以通过启用
clang++ -std=c++14 -stdlib=libc++ -fsanitize=thread *.cpp -pthread
这可能在某种程度上是一个重复的问题,但我找不到任何东西,所以如果真的是重复的,我很抱歉。无论如何,这应该是一个初学者的问题。
我在玩一个简单的"计数器"类,比如文件中的内联
柜台.hpp:
#ifndef CLASS_COUNTER_HPP_
#define CLASS_COUNTER_HPP_
#include <mutex>
#include <string>
#include <exception>
class Counter
{
public:
explicit Counter(std::size_t v = 0) : value_{v} {}
std::size_t value() const noexcept { return value_; }
// void increment() { ++value_; } // not an atomic operation : ++value_ equals value_ = value_ + 1
// --> 3 operations: read, add, assign
void increment() noexcept
{
mutex_.lock();
++value_;
mutex_.unlock();
}
// void decrement() noexcept
// {
// mutex_.lock();
// --value_; // possible underflow
// mutex_.unlock();
// }
void decrement()
{
std::lock_guard<std::mutex>{mutex_};
if (value_ == 0)
{
std::string message{"New Value ("+std::to_string(value_-1)+") too low, must be at least 0"};
throw std::logic_error{message};
}
--value_;
}
private:
std::size_t value_;
std::mutex mutex_;
};
#endif
在main.cpp中,Counter实例应该递增和递减同时:
main.cpp:
#include <iostream>
#include <iomanip>
#include <array>
#include <thread>
#include <exception>
#include "Counter.hpp"
int
main ()
{
Counter counter{};
std::array<std::thread,4> threads;
auto operation = [&counter]()
{
for (std::size_t i = 0; i < 125; ++i)
counter.increment();
};
// std::for_each(begin(threads),end(threads),[&operation](auto& val) { val = std::thread{operation}; });
std::cout << "Incrementing Counter (" << std::setw(3) << counter.value() << ") concurrently...";
for (auto& t : threads)
{
t = std::thread{operation};
}
for (auto& t : threads)
t.join();
std::cout << " new value == " << counter.value() << 'n';
auto second_operation = [&counter]()
{
for (std::size_t i = 0; i < 125; ++i)
{
try
{
counter.decrement();
}
catch(const std::exception& e)
{
std::cerr << "n***Exception while trying to decrement : " << e.what() << "***n";
}
}
};
std::cout << "Decrementing Counter (" << std::setw(3) << counter.value() << ") concurrently...";
for (auto& t : threads)
t = std::thread{second_operation};
for (auto& t : threads)
t.join();
std::cout << " new value == " << counter.value() << 'n';
return 0;
异常处理似乎按预期工作,我对它的理解是std::lock_guard应该保证在lock_guad超出范围时解锁互斥对象。
然而,它似乎比这更复杂。虽然增量正确地得到了"500"的最终值,但应该得到"0"的减量却不起作用。结果将介于"0"answers"16"之间
如果改变时间,例如使用valgrind,它似乎每次都能正确工作。
我能够将问题精确定位为std::lock_guard的使用。如果我将递减()函数定义为:
void decrement() noexcept
{
mutex_.lock();
--value_; // possible underflow
mutex_.unlock();
}
一切都很好(只要没有下溢)。但一旦我做了一个简单的更改:
void decrement() noexcept
{
std::lock_guard<std::mutex>{mutex_};
--value_; // possible underflow
}
行为就像我上面描述的那样。我想我并没有真正理解std::lock_guard的行为和使用案例。如果你能为我指明正确的方向,我将不胜感激!
程序通过clang++ -std=c++14 -stdlib=libc++ *.cpp -pthread
进行编译。
std::lock_guard<std::mutex>{mutex_};
不创建本地。它创建了一个临时的,在语句末尾被销毁。这意味着您的价值不受锁的保护。锁定防护装置必须是本地的:
void decrement() noexcept
{
std::lock_guard<std::mutex> guard {mutex_};
--value_; // possible underflow
}
问题在于线路
std::lock_guard<std::mutex>{mutex_};
不创建变量,而是创建一个立即被再次销毁的临时lock_guard
对象。你可能想写的是:
std::lock_guard<std::mutex> guard{mutex_};
这会创建一个类型为lock_guard
的变量,名为guard
,当它离开作用域时(即在函数末尾),它会被销毁。本质上,您忘记了命名变量。
- 编译C++时未定义的引用
- vscode g++链路故障:体系结构x86_64的未定义符号
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 对C宏的未定义引用,但在定义它时会出现重新定义错误
- 未定义的引用在哪里
- 编译时的 CImg 库返回对"__imp_SetDIBitsToDevice"的未定义引用
- 对Py_Initialize()的未定义引用
- c++11评估顺序(未定义的行为)
- 使用mysql c++连接器的未定义引用
- 从python调用openMP共享库时,未定义opnMP函数
- 在 Mac 上使用 CMAKE 将 FFTW 和 FFTWPP 链接到项目中时未定义的符号
- Cmake 链接问题:未定义对 Button::mousePressEvent(QGraphicsSceneMouseE
- 未定义的引用 .. 使用 OpenCV 编译 C++ 代码时,从命令行
- 具有外部"c"和程序集的未定义函数
- 此增量后语句是否会导致未定义的行为?
- 尝试调用 .h 文件中定义的变量时出现变量未定义错误
- 在C++中使用内联方法时出现未定义的符号错误
- 对 Scalar ::Scalar() 的未定义引用