Multithreading Linux内核等待队列和列表之间的正确交互
我正在编写一个Linux内核模块,其中包含一个从不同进程上下文读取/写入的列表,我觉得在用户空间中缺少了相当于pthread_cond_wait()和co.的功能 天真地,我可能会这样写:Multithreading Linux内核等待队列和列表之间的正确交互,multithreading,linux-kernel,Multithreading,Linux Kernel,我正在编写一个Linux内核模块,其中包含一个从不同进程上下文读取/写入的列表,我觉得在用户空间中缺少了相当于pthread_cond_wait()和co.的功能 天真地,我可能会这样写: static LIST_HEAD(request_list); static DEFINE_MUTEX(request_list_mutex); static DECLARE_WAIT_QUEUE_HEAD(request_list_post_wq); static void post_request(re
static LIST_HEAD(request_list);
static DEFINE_MUTEX(request_list_mutex);
static DECLARE_WAIT_QUEUE_HEAD(request_list_post_wq);
static void post_request(request_t *request)
{
mutex_lock(request_list_mutex);
list_add(request, request_list);
mutex_unlock(request_list_mutex);
wake_event(request_list_post_wq);
}
static void wait_and_consume_request()
{
mutex_lock(request_list_mutex);
if(list_empty(request_list)) {
mutex_unlock(request_list_mutex);
wait_event(request_list_post_wq, !list_empty(request_list));
mutex_lock(request_list_mutex);
}
// do something with request
mutex_unlock(request_list_mutex);
}
然而,这看起来像是在消费者函数中有一个竞争条件,即在非空列表中唤醒,然后在有多个消费者的情况下重新获取互斥。同时,我必须在等待之前释放互斥锁,否则将无法向列表中添加任何内容
我考虑编写一个函数来锁定请求列表,只有当它仍然为空时才解锁,并将其用作等待事件的条件。。。但是在谷歌上我看到了很多人写wait_event(…..,!list_empty(…)的例子,所以我肯定遗漏了什么?另一个人建议的helper函数根本不需要:
static int list_is_not_empty()
{
int rv = 1;
mutex_lock(request_list_mutex);
rv = !list_empty(request_list);
mutex_unlock(request_list_mutex);
return rv;
}
没有必要仅仅为了查看列表是否为空而锁定列表。简单地说:
static void wait_and_consume_request()
{
wait_event(request_list_post_wq, !list_empty(request_list));
mutex_lock(request_list_mutex);
if(!list_empty(request_list)) {
// do something with request
}
mutex_unlock(request_list_mutex);
}
但这并不能保证您实际使用了一个请求。如果我们确实希望确保只使用一个请求,那么:
static void wait_and_consume_request()
{
mutex_lock(request_list_mutex);
while(list_empty(request_list)) {
mutex_unlock(request_list_mutex);
wait_event(request_list_post_wq, !list_empty());
lock_mutex();
}
// do something with request
mutex_unlock(request_list_mutex);
}
这里是drivers/misc/carma/carma fpga.c中内核的一个真实示例(我刚刚使用了我看到的第一个示例)
spin_lock_irq(&priv->lock);
/* Block until there is at least one buffer on the used list */
while (list_empty(used)) {
spin_unlock_irq(&priv->lock);
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
ret = wait_event_interruptible(priv->wait, !list_empty(used));
if (ret)
return ret;
spin_lock_irq(&priv->lock);
}
/* Grab the first buffer off of the used list */
dbuf = list_first_entry(used, struct data_buf, entry);
list_del_init(&dbuf->entry);
spin_unlock_irq(&priv->lock);