R..*_*R.. 6 c synchronization pthreads linked-list
我正在尝试在pthreads环境中实现C中的(特殊类型)双向链表,但是只使用C-wrapped同步指令,如原子CAS等,而不是pthread原语.(列表的元素是固定大小的内存块,几乎肯定不适合pthread_mutex_t它们内部.)我实际上并不需要完全任意的双向链表方法,只有:
因此,描述此数据结构的更好方法可能是队列/ fifo,可以删除队列中的项目.
是否有标准方法来同步这个?我遇到了可能出现的死锁问题,其中一些问题可能是所涉及的算法所固有的,其他问题可能源于这样一个事实,即我正试图在有限的空间内工作,并对我能做的事情有其他限制.
编辑:特别是,如果要同时删除相邻的对象,我会坚持做什么.大概在删除对象时,您需要获取列表中上一个和下一个对象的锁定,并更新它们的下一个/ prev指针以指向彼此.但是如果任何一个邻居已经被锁定,这将导致死锁.我试图找出一种方法,任何/所有发生的删除可以走在列表的锁定部分,并确定当前正在删除过程中的最大子列表,然后锁定该子列表旁边的节点,以便整个子列表整体被移除,但我的头开始受伤.. :-P
结论(?):为了跟进,我确实有一些我想要工作的代码,但我也对理论问题感兴趣.每个人的答案都非常有用,并且结合了我在这里表达的限制之外的细节(你真的不想知道要删除的指针来自何处以及那里涉及的同步!)我现在决定放弃本地锁定代码并专注于:
再次感谢所有给出答案的人.如果我的实验不顺利,我可能会回到所概述的方法(特别是弗拉德),然后再试一次.
为什么不应用粗粒度的锁?只需锁定整个队列即可.
更精细(但不一定更有效,取决于您的使用模式)解决方案将分别使用读写锁定来进行读写.
对我来说,使用无锁操作似乎不是一个好主意.想象一下,某些线程正在遍历您的队列,同时删除"当前"项.无论您的遍历算法包含多少其他链接,所有项目都可能被删除,因此您的代码将无法完成遍历.
比较和交换的另一个问题是,使用指针,您永远不知道它是否真正指向相同的旧结构,或者旧结构已被释放,并且在同一地址分配了一些新结构.这可能是您的算法的问题,也可能不是.
对于"本地"锁定的情况(即,可以单独锁定每个列表项),一个想法是使锁定.对锁进行排序可确保无法实现死锁.所以你的操作是这样的:
通过指针p删除前一项:
插入到开头:
这似乎是正确的,但我没有尝试这个想法.
从本质上讲,这使双链表工作就好像它是一个单链表.
如果你没有指向前一个列表元素的指针(当然通常就是这种情况,因为几乎不可能将这样的指针保持在一致状态),你可以执行以下操作:
通过指针c删除要删除的项目:
请注意,只有指向某个列表项的指针无法确保该项未被释放,因此您需要进行一种引用计数,以便在您尝试锁定该项时不会销毁该项.
请注意,在最后一个算法中,重试次数是有界的.实际上,新项目不能出现在c的左侧(插入位于最右侧位置).如果我们的步骤5失败,因此我们需要重试,这只能通过同时从列表中删除p来引起.这样的移除可以发生不超过N-1次,其中N是列表中c的初始位置.当然,这种最坏的情况不太可能发生.
请不要严厉对待这个答案,但不要这样做.
你几乎肯定会遇到错误,并且很难发现错误.使用pthreads锁原语.他们是您的朋友,并且由深刻理解您选择的处理器提供的内存模型的人编写.如果你试图用CAS和原子增量等做同样的事情,你几乎肯定会犯一些你不会发现的微妙错误,直到它为时已晚.
这里有一个代码示例来帮助说明这一点.这个锁有什么问题?
volatile int lockTaken = 0;
void EnterSpinLock() {
while (!__sync_bool_compare_and_swap(&lockTaken, 0, 1) { /* wait */ }
}
void LeaveSpinLock() {
lockTaken = 0;
}
Run Code Online (Sandbox Code Playgroud)
答案是:释放锁时没有内存障碍,这意味着锁中执行的某些写操作可能在下一个线程进入锁之前没有发生.哎呀!(也可能存在更多错误,例如,该函数不会在自旋循环内执行适合平台的产量,因此极大地浪费了CPU周期.&c.)
如果将双链表实现为带有sentinal节点的循环列表,则只需要执行两个指针分配以从列表中删除项目,并且只需要四个添加项目.我相信你能负担得起这些指针分配的写得很好的独占锁.
请注意,我假设您不是少数几个深刻理解记忆模型的人之一,因为世界上只有极少数记忆模型.如果你是这些人中的一员,那么即使你无法弄明白这一事实也应该表明它是多么棘手.:)
我也假设你问这个问题,因为你有一些你真正喜欢的代码.如果这只是一个学术练习,以便更多地了解线程(可能作为成为深层低级并发专家的一步),那么无论如何,请忽略我,并对内存细节进行研究您要定位的平台模型.:)