尝试我的运气,使无锁的单链表实现。
typedef _Atomic struct _node
{
void *data;
struct _node *next;
} Node;
这是否也使结构的所有成员都具有原子_Atomic?
void add_head ( Linked_list* list, void* data )
{
if ( debugging )
{
printf ( "%sn", __func__ );
}
Node *node = ( Node* ) calloc ( 1, sizeof (Node ) );
//init_node_mutex(node);
//lock_node_mutex(node);
atomic_exchange ( &node->next, NULL );
atomic_exchange ( &node->data, data );
if ( list->head == NULL )
{
Node* the_tail = atomic_load ( &list->tail );
// lock_node_mutex ( the_tail );
atomic_exchange ( &node->next, NULL );
atomic_compare_exchange_weak ( &list->tail, the_tail, node );
//unlock_node_mutex ( the_tail );
}
else
{
Node* the_next = atomic_load ( &node->next );
// lock_node_mutex ( the_next );
atomic_compare_exchange_weak ( &node->next, the_next, list->head );
// unlock_node_mutex ( the_next );
}
Node* the_head = atomic_load ( & list->head );
//lock_node_mutex ( the_head );
atomic_store ( &list->head, node );
atomic_store ( &list->current, node );
//unlock_node_mutex ( the_head );
//unlock_node_mutex(node);
atomic_fetch_add ( &list->size, 1 );
}
用法是否atomic_load和atomic_store正确?
好吧,我争论过是将其作为"评论"还是"答案"发布,但我要在这里休息。
我的直觉相当尖叫,"你正在执行的单个操作是否是"原子的"并不重要,因为你连续执行许多操作,以完成你最终想要做的事情。即使这些单独的步骤是"原子的",整个操作也不是。
"原子"操作是使用专门的机器指令(例如 x86 上的LOCK
前缀或大铁上的"比较和交换"指令)来执行单个操作的操作,以便没有其他 CPU(或内核)干扰该单个操作。
但是,你不能在"单个指令"中做你想做的事情,无论是否原子。
因此,我诚挚地建议你现在放弃你现在的课程,把那些"互斥"调用放回去,去掉"互斥"。您的代码(以及所有像这样的代码...)需要这些互斥体。在我看来,你正在追逐一只白兔在死胡同里。
(顺便说一下,"互斥"操作有时会很好地利用这些"原子指令",所以它们可能比你担心的要高效得多。
除了@MikeRobinson的评论之外,我想补充一点,虽然你的代码是"无锁的",因为它不包含任何明确的锁使用,但它现在(有点讽刺地)不再是线程安全的。编写无锁代码非常困难。我建议通读本文以获得对世界的鸟瞰图,然后阅读本文以获取一些细节或本书的第7章(这是C++)。您可以随时查看Boost.LockFree的来源以获取灵感。