使用未来的 C++ 在运行时出现分段错误

segmentation fault at runtime using future c++

在运行时,代码片段末尾的注释指令出现分段错误。 我是否正确使用了未来?队列在单线程中工作(似乎工作)正常。当我尝试异步弹出元素时,出现分段错误。

#include <iostream>
#include <memory>
#include <atomic>
#include <thread>
#include <future>
#include <assert.h>
using std::cout;

template<typename T>
class Queue
{ private:
    struct element
    {
      T data;
      element* previous;
      element():previous(nullptr){}
    };

    std::atomic<element*> head;
    std::atomic<element*> tail;
  public:
    Queue():head(new element), tail( head.load() ){}

    ~Queue()
    {
      while( element* const old_head = head.load() )
      {
        head.store(old_head->previous);
        delete old_head;
      }
    }

    T* pop()
    {
      element* old_head = head.load();
      if( old_head == tail.load() ){return nullptr;}

      head.store( old_head->previous );

      T* const result = new T(old_head->data);
      delete old_head;
      return result;
    }

    void push(T new_value)
    {
      element* new_data = new element;
      new_data->data = new_value;

      element* const old_tail = tail.load();
      std::swap(old_tail->data, new_value);

      element* p = new element;
      old_tail -> previous = p;
      tail.store(p);
      assert( tail.load() != head.load() );
    }

 };

int main()
{
  Queue<double> aDoubleQueue;

  assert( nullptr == aDoubleQueue.pop() );
  aDoubleQueue.push(17.0);
  assert( 17.0 == *aDoubleQueue.pop() );
  aDoubleQueue.push(17.0);
  aDoubleQueue.push(19.0);
  assert( 17.0 == *aDoubleQueue.pop() );
  assert( 19.0 == *aDoubleQueue.pop() );
  assert( nullptr == aDoubleQueue.pop() );

  aDoubleQueue.push(17.0);
  std::future< double* > popped = std::async(&Queue<double>::pop, &aDoubleQueue );
  popped.wait();  
  if( nullptr == popped.get()){ cout << "\n nullptr";}
  else
  { cout << "\n !nullptr";
    // double* a = popped.get(); // causes a segmentation fault
  }
  return 0;
}

std::future::get() 的文档说

this member function shall be called once at most for every future

你调用了两次它就失效了。它抛出一个你不处理的异常。

根据 cppreference,valid 在调用 future::get() 方法后是 false。第二次调用导致抛出异常,因为 valid 在第一次调用后设置为 false

我也是期货新手。所以我可能会离开。 您需要 poppedc.wait() 吗?

我的理解是popped.get会自动等待

如前所述,您不应调用 get 两次。我很想在第二个 get 上放置一个断点,然后单步进入代码以查看段错误。我敢打赌 get 尝试 return 一个指向已删除数据的指针。

您使用 Queue 是安全的,但也很危险。最简单的解释就是线程中对队列的访问没有交错。

对命中的反应。 否。线程 1 一直运行到它启动线程 2,然后线程 1 立即停止。线程 2,然后运行完成。然后线程 1 再次启动。不能有竞争条件,因为流程不允许。