我想要一个并发数据结构,其工作方式类似于单链列表,并且只需要执行append
和remove_iterator
操作。最后,一个线程将iterate
所有节点。从我的研究中,我得到了一个implementation,它具有带有单个链接列表的append
,remove_value
和search_value
操作。它基于Harris' algorithm。
问题在于,在哈里斯算法中,remove_value
仅标记逻辑删除的节点,而没有实际删除它。 search_value
实际上负责删除逻辑上已删除的节点。但是由于我的用例没有search
操作。我保留了很长的列表,其中包含许多被逻辑删除的节点。只是因为多节点删除的所有工作都放在单个线程内的iterate
操作上,所以多线程的速度效率并不高。
我想知道是否还有其他符合我需要的实施方式。任何建议表示赞赏。
如果不是,我想知道是否可以使用带有无锁堆栈实现的free-list来为这种特殊情况实现某些功能。在这种情况下,append
操作将成为pop
空闲列表,将值放入节点,如果为空则追加到我们的列表。 remove_iterator
操作将标记为逻辑上已删除的节点,而push
则是指向空闲列表的节点指针。
我认为无锁堆栈如果相当容易实现。我可以在线使用一些implementations。
记住一些代码。
struct node_t {
node_t *next;
int deleted;
val_t val;
};
struct list_t {
node_t *head;
};
struct fl_node_t {
node_t *padding_1;
int padding_2;
fl_node_t *next; // assume sizeof(val_t) >= sizeof(fl_node_t*);
};
struct free_list_t {
fl_node_t * head;
};
void append(val_t val) {
fl_node_t *fl_head;
fl_node_t *fl_next;
node_t *head;
node_t *new_node
/* Try insert to one of the node in free-list */
if (free_list.head) {
do {
fl_head = free_list.head;
next = fl_head->next;
} while(!CAS(&free_list.head, fl_head, fl_next));
if (fl_head) {
fl_head->node->val = val;
return;
}
}
/* Append to head */
new_node = malloc(sizeof(node_t));
new_node.val = val;
new_node.deleted = 0;
do {
head = list.head;
new_node.next = head;
} while(!CAS(&list.head, head, new_node));
}
void remove(node_t *node) {
fl_node_t *fl_node;
fl_node_t *fl_head;
/* Mark logically deleted */
node->deleted = 1;
fl_node = (fl_node_t*) node;
/* Add to free-list */
do {
fl_head = free_list.head;
fl_node->next =fl_head;
} while(!CAS(&free_list.head, fl_head, fl_node));
}
答案 0 :(得分:2)
当涉及到“释放锁和等待释放”数据结构时,不要尝试重新发明轮子或修复某些问题,而是花很多时间来尝试证明它是正确的,如果可能的话,请使用一个经过验证的现有实现。
无锁实现很难做到正确,也很难证明正确。在实践中,出于性能原因,我们不得不使用它们,因为它们可以反复移动,然后有一天爆炸。从这里改编的实现取得了很大的成功
他还参考了其他库,并提供了对并发编程的深入了解。非常值得一读。
答案 1 :(得分:0)
我在github上找到了gavra0的实现。通过添加空闲列表的修改(使用无锁堆栈实现),我得到了一些有效的代码。
存储库为https://github.com/buszk/ConcLinkedList。实现是在dev
分支的link中。