簡體   English   中英

std :: lock_guard導致未定義的行為

[英]std::lock_guard causing undefined behavior

編輯:看起來,問題是我實際上並沒有創建一個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實例應該同時遞增和遞減:

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_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_}; 不創建本地。 它創建了一個臨時語句,在語句結束時被銷毀。 這意味着您的值不受鎖的保護。 鎖定裝置必須是本地的:

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 ,當它離開作用域時會被銷毀(即在函數結束時。實際上,你忘了為你的變量命名。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM