使用未来的c ++在运行时分段错误

时间:2015-07-22 06:28:15

标签: c++ multithreading c++11 future

我在运行时的代码片段末尾的注释指令上遇到了分段错误。 我未来使用得当吗?队列在单线程中工作(似乎工作)很好。当我尝试异步弹出元素时,我遇到了分段错误。

#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;
}

3 个答案:

答案 0 :(得分:2)

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

  

这个成员函数最多每次调用一次

你把它叫两次,这个时候它无效。它引发了一个你无法处理的异常。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

我也是未来的新手。所以我可能会离开。 你需要poppedc.wait()?

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

正如所指出的那样,你不应该打两次电话。我的诱惑是在第二步获取一个断点并在代码中单步执行以查看段错误。我会打赌任何尝试返回指向已经删除的数据的指针。

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

对点击的回应。 不会。线程1运行直到它开始线程2,线程1然后立即停止。线程2,然后运行完成。然后线程1再次启动。没有竞争条件,因为流量不允许它。