【发布时间】:2018-07-21 09:41:30
【问题描述】:
我正在尝试使用shared_ptr 在 C++ 中实现 基于惰性并发列表的集合。我的理由是unreachable nodes 将被最后一个shared_ptr 自动释放。据我了解,shared_ptr's reference count 上的递增和递减操作是原子的。这意味着只有参考节点的 last shared_ptr 应该为该节点调用 delete/free。我为多线程运行程序,但我的程序因错误double free called 或Segmentation Fault(SIGSEGV) 而崩溃。我不明白这怎么可能。下面给出的是我的实现代码,方法名称表示它们的预期操作。
#include<thread>
#include<iostream>
#include<mutex>
#include<climits>
using namespace std;
class Thread
{
public:
std::thread t;
};
int n=50,ki=100,kd=100,kc=100;`/*no of threads, no of inserts,deletes & searches*/`
class Node
{
public:
int key;
shared_ptr<Node> next;
bool marked;
std::mutex nodeLock;
Node() {
key=0;
next = nullptr;
marked = false;
}
Node(int k) {
key = k;
next = nullptr;
marked = false;
}
void lock() {
nodeLock.lock();
}
void unlock() {
nodeLock.unlock();
}
~Node()
{
}
};
class List {
shared_ptr<Node> head;
shared_ptr<Node> tail;
public:
bool validate(shared_ptr<Node> pred, shared_ptr<Node> curr) {
return !(pred->marked) && !(curr->marked) && ((pred->next) == curr);
}
List() {
head=make_shared<Node>(INT_MIN);
tail=make_shared<Node>(INT_MAX);
head->next=tail;
}
bool add(int key)
{
while(true)
{
/*shared_ptr<Node> pred = head;
shared_ptr<Node> curr = pred->next;*/
auto pred = head;
auto curr = pred->next;
while (key>(curr->key))
{
pred = curr;
curr = curr->next;
}
pred->lock();
curr->lock();
if (validate(pred,curr))
{
if (curr->key == key)
{
curr->unlock();
pred->unlock();
return false;
}
else
{
shared_ptr<Node> newNode(new Node(key));
//auto newNode = make_shared<Node>(key);
//shared_ptr<Node> newNode = make_shared<Node>(key);
newNode->next = curr;
pred->next = newNode;
curr->unlock();
pred->unlock();
return true;
}
}
curr->unlock();
pred->unlock();
}
}
bool remove(int key)
{
while(true)
{
/*shared_ptr<Node> pred = head;
shared_ptr<Node> curr = pred->next;*/
auto pred = head;
auto curr = pred->next;
while (key>(curr->key))
{
pred = curr;
curr = curr->next;
}
pred->lock();
curr->lock();
if (validate(pred,curr))
{
if (curr->key != key)
{
curr->unlock();
pred->unlock();
return false;
}
else
{
curr->marked = true;
pred->next = curr->next;
curr->unlock();
pred->unlock();
return true;
}
}
curr->unlock();
pred->unlock();
}
}
bool contains(int key) {
//shared_ptr<Node> curr = head->next;
auto curr = head->next;
while (key>(curr->key)) {
curr = curr->next;
}
return curr->key == key && !curr->marked;
}
}list;
void test(int curr)
{
bool test;
int time;
int val, choice;
int total,k=0;
total=ki+kd+kc;
int i=0,d=0,c=0;
while(k<total)
{
choice = (rand()%3)+1;
if(choice==1)
{
if(i<ki)
{
val = (rand()%99)+1;
test = list.add(val);
i++;
k++;
}
}
else if(choice==2)
{
if(d<kd)
{
val = (rand()%99)+1;
test = list.remove(val);
d++;
k++;
}
}
else if(choice==3)
{
if(c<kc)
{
val = (rand()%99)+1;
test = list.contains(val);
c++;
k++;
}
}
}
}
int main()
{
int i;
vector<Thread>thr(n);
for(i=0;i<n;i++)
{
thr[i].t = thread(test,i+1);
}
for(i=0;i<n;i++)
{
thr[i].t.join();
}
return 0;
}
我无法弄清楚上面的代码有什么问题。错误每次都不一样,其中一些只是SEGFAULTS或
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
您能否指出我在上面的代码中做错了什么?以及如何修复该错误?
编辑:添加了一个非常粗略的test function,它随机调用三个list methods。此外,线程数和每个操作的数量是全局声明的。粗略的编程,但它重新创建了 SEGFAULT。
【问题讨论】:
-
至于使用
shared_ptr,很酷。我向实验致敬。 -
@user4581301,我应该用包含
main的完整代码打开另一个问题吗?还是直接发布在 cmets 中? -
@DeeJay 使用
main功能编辑您当前的帖子。没有必要开始另一个问题。也不要在 cmets 中发布代码。 -
@user4581301,不,但这是此列表背后的主要思想。一旦锁定
pred & curr,就会调用“验证”函数来检测任何同步冲突。validate检查pred & curr是否没有被标记并且 pred 仍然指向 curr。即使pred或curr被删除,它们也会被首先标记(删除方法)。因此 Lazy Synchronization 是 List 的名称。 -
@user4581301 添加了必要的代码编辑。
标签: c++ multithreading segmentation-fault shared-ptr double-free