gpt4 book ai didi

c++ - std::lock_guard 导致未定义的行为

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:01:30 26 4
gpt4 key购买 nike

编辑: 看起来,问题是我实际上并没有创建一个 lock_guard 的本地实例,而只是一个匿名的临时实例,它立即再次被销毁,如下面的评论所指出的。

Edit2:启用 clang 的线程清理器有助于在运行时查明这些类型的问题。它可以通过

启用
clang++ -std=c++14 -stdlib=libc++ -fsanitize=thread *.cpp -pthread

这在某种程度上可能是一个重复的问题,但我找不到任何东西,所以如果它真的是重复的,我很抱歉。无论如何,这应该是一个初学者问题。

我正在玩一个简单的“Counter”类,比如在文件中内联

计数器.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 实例应该被递增和递减同时:

主要.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_guard 超出范围就解锁互斥量。

然而,它似乎比这更复杂。虽然递增正确地导致最终值为“500”,但递减(本应为“0”)却没有结果。结果将介于“0”和“16”之间。

如果时间发生变化,例如通过使用 valgrind,它似乎每次都能正常工作。

我能够查明问题出在 std::lock_guard 的使用上。如果我这样定义 decrement() 函数:

      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_};不创建本地。它创建一个临时文件,在语句结束时销毁。这意味着您的值(value)不受锁的保护。锁守卫必须是本地的:

void decrement() noexcept
{
std::lock_guard<std::mutex> guard {mutex_};
--value_; // possible underflow
}

关于c++ - std::lock_guard 导致未定义的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34612707/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com