我正在为linux内核开发一个补丁。我必须使用几个 列表,我必须保护'以防止并发修改 多核机器。我正在尝试使用自旋锁来达到这个目标,但是 有些东西我无法理解。我必须锁定一个条目 list(我正在使用linux默认的链表实现)和它 可能会发生一个进程调用一个系统调用来删除一个元素 列表,而因为某些元素被锁定的相同元素 实际上正在进行修改。如果我插入一个螺旋锁 在列表条目内,如果进程设法删除它会发生什么 有人在上面旋转锁定?我应该锁定整个清单吗? 我正在寻找一段可以解释如何处理这个问题的代码 情况。
例如,此代码不起作用(请参阅最后一行的注释 代码):
struct lista{
int c;
spinlock_t lock;
struct list_head;
}
spinlock_t list_lock;
struct lista lista;
//INSERT
struct lista* cursor;
struct lista* new = (struct lista*) kmalloc(sizeof(struct lista),GFP_KERNEL);
/*do something*/
spin_lock(&list_lock); //Lock on the whole list
list_for_each_entry(cursor,&lista.list,list){
if (cursor->c == something ){
...
spin_unlock(&list_lock) //unlock
spin_lock(&cursor->lock) // Lock on list entry
list_add(&new->list, &lista.list);
spin_unlock(&cursor->lock) // unlock of the list entry
...
}
}
//REMOVAL
struct lista* cursor;
spin_lock(&list_lock);
list_for_each_entry(cursor,&lista.list,list){
if (cursor->c == something ){
...
spin_unlock(&list_lock) //unlock
spin_lock(&cursor->lock) // Lock on list entry
list_del(&cursor.list,&lista.list);
spin_unlock(&cursor->lock) // unlock of the list entry
kfree(cursor); //WHEN THE ENTRY IS FREED SOMEONE COULD HAVE TAKEN THE LOCK SINCE IT IS UNLOCKED
...
}
}
你能帮帮我吗?
答案 0 :(得分:3)
在您删除该项目之前,请勿释放list_lock
。
你最终可能会遇到一个稍微尴尬的程序:
变体:使用读写器锁进行列表锁定。
寻找修改列表项的线程会使读取器锁定;这允许多个线程并行地在列表上操作。
寻找删除列表项的线程采用编写器锁;这等待所有读者退出并阻止它们直到你释放它们。在这种情况下,您仍然必须保持列表锁定,直到您完成删除项目
通过这种方式,您可以避免上面的第2步。这似乎在概念上更清晰,因为您不需要解释看起来毫无意义的锁定/释放。
答案 1 :(得分:0)
你几乎肯定不应该使用自旋锁,除非有来自硬IRQ上下文的并发访问。改用互斥锁。
列表中最简单的选项就是在操作时锁定整个列表。不要担心每个项目的锁定,除非你发现你需要它的列表锁定有足够的争用(在这种情况下,你可能想要看看使用RCU,无论如何)。
答案 2 :(得分:0)
您的列表头不需要是struct lista
,它应该只是struct list_head
。请注意,您继续使用&lista.list
,这应该只是list_head
名为“列表”或其他内容。例如,请参阅drivers/pci/msi.c
中的代码,注意dev->msi_list
只是list_head
,而不是struct msi_desc
。
您无法安全地删除列表锁定,然后获取光标锁定。删除列表锁定之后但在获得光标锁定之前,可能会有其他人进来并释放光标。你可以玩弄锁,但非常容易出错。
对于整个列表,你几乎肯定只需要一个锁,而且没有每个项锁。除非您需要从中断上下文中操作列表,否则列表锁应该是mutex
。
答案 3 :(得分:0)
如果你不处理设备和/或内核的关键部分,其中必须使用自旋锁(因为它禁用抢占和中断(根据请求)),那么Y 2使用自旋锁,这将不一定关闭你的先发制人中断。 在列表中使用信号量或互斥量不是列表项看起来更好的解决方案。