Я пытаюсь реализовать набор Lazy Concurrent List-based Set на C++, используя shared_ptr
. Я полагаю, что unreachable nodes
будет автоматически освобожден последним shared_ptr
. Насколько я понимаю, операции увеличения и уменьшения для shared_ptr's reference count
являются атомарными. Это означает, что только последний shared_ptr со ссылкой на узел должен вызывать delete/free для этого узла. Я запустил программу для нескольких потоков, но моя программа аварийно завершает работу с ошибкой double free called
или просто с ошибкой сегментации (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)
Не могли бы вы указать, что я делаю неправильно в приведенном выше коде? И как исправить эту ошибку?
EDIT: Добавлен очень грубый test function
, который случайным образом вызывает три list methods
. Кроме того, количество потоков и количество каждой операции объявляются глобально. Грубое программирование, но оно воссоздает SEGFAULT.
shared_ptr
для этого, круто. Я приветствую эксперименты. - person user4581301   schedule 11.02.2018main
? Или просто написать в комментариях? - person Dee Jay   schedule 11.02.2018main
. Нет необходимости начинать еще один вопрос. Также не размещайте код в комментариях. - person PaulMcKenzie   schedule 11.02.2018pred & curr
, будет вызвана функция проверки для обнаружения любых конфликтов синхронизации.validate
проверяет, не был ли отмеченpred & curr
и pred все еще указывает на curr. Даже еслиpred
илиcurr
будут удалены, они будут отмечены первыми (метод удаления). Отсюда и название списка Lazy Synchronization. - person Dee Jay   schedule 11.02.2018