使用未来的 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 再次启动。不能有竞争条件,因为流程不允许。
在运行时,代码片段末尾的注释指令出现分段错误。 我是否正确使用了未来?队列在单线程中工作(似乎工作)正常。当我尝试异步弹出元素时,出现分段错误。
#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 再次启动。不能有竞争条件,因为流程不允许。