Chinaunix首页 | 论坛 | 博客
  • 博客访问: 50249
  • 博文数量: 21
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-15 13:27
文章分类
文章存档

2014年(21)

我的朋友

分类: 其他平台

2014-09-01 13:22:52

原文地址:等待队列(简单使用) 作者:511929155

等待队列(使用篇)

1,基本概念

什么是阻塞操作?

这个好理解,其实就是对设备的操作没成功,进程进入等待状态,等待系统唤醒。

在代码的层面理解: 运行到某代码(如某read()操作), 进程挂在那了,不再往下运行。

                 


下面是我对等待队列的理解:

如上图,一个FIFO设备的读写,需要两个wait_queue_head,分别对应读、写。

等待读、写的进程分别挂在这两个wait_queue_head后面。

注:其实FIFO的读(或写)就是某种资源,等待队列的作用就是把等待该资源的进程都挂在上面,然后进程本身进入等待状态。

 2,实例

如果不关心具体实现,只需要了解怎么使用等待队列的话,所需要做的工作还是很少的。(原理后续再研究)

 

假设一个my_fifo设备,实现: 如果没有进程写,则试图读的进程会被阻塞

1) 该设备的结构体

点击(此处)折叠或打开

  1. structmyfifo_dev
  2. {
  3.      /*其他成员这里就不列出了*/

  4. wait_queue_head_t r_write; // 阻塞写的等待队列头
  5. wait_queue_head_t r_read; // 阻塞读的等待队列头

  6. };

2) 等待队列的初始化  

从上文我们知道,这个就是等待队列3类操作中的第1类了  :)

问1:在哪里初始化呢?   

答:当然是在内核模块加载函数中。

问2: 怎么初始化?

答:调用init_waitqueue_head(  r_wait )。  (这个r_wait是怎么来的?,呵呵,设备结构体中)

问3:关于初始化还有别的东西吗?

     答:好像没有了,就这么简单。

 3) 将一个进程加入等待队列(阻塞)

根据前面的功能描述,因为是read()操作被阻塞,所以需要在read()函数中做修改,如下:

  1. static ssize_t mydev_read(struct file*filp, char* buf, size_t len,loff_t* off)
  2. {
  3.     if(wait_event_interruptible(r_read,flag!=0) ) // 就是这里
  4.         return-ERESTARTSYS;

  5.     if(down_interruptible(&sem) )
  6.         return-ERESTARTSYS;

  7.     flag= 0;
  8.     if(copy_to_user(buf,data,len) )
  9.     {
  10.         up(&sem);
  11.         return-EFAULT;
  12.     }
  13.     up(&sem);
  14.     returnlen;
  15. }
4) 将一个进程从等待队列移出(唤醒)

点击(此处)折叠或打开


根据前面的功能,只要有进程执行write()操作,则就会唤醒被read()阻塞的进程。所以,需要在write()函数中做修改:

  1. ssize_t mydev_write(struct file *file,const char __user *buf, size_t count, loff_t *f_pos)
  2. {
  3.    ssize_t ret = 0;
  4.    pr_info("mydev_write!\n");
  5.    pr_info("writing %d bytes\n", count);
  6.  
  7.    if( down_interruptible(&sem) )
  8.         return-ERESTARTSYS;

  9.    if (count > 127)
  10.        return -ENOMEM;

  11.    if (count < 0)
  12.        return -EINVAL;

  13.    if (copy_from_user(data, buf, count))
  14.    {
  15.        up(&sem);
  16.        return -EFAULT;
  17.    }
  18.    else {
  19.        data[127] = '\0';
  20.        pr_info("kernel received: %s\n", data);
  21.        ret = count;

  22.    }

  23.    up(&sem);

  24.    flag = 1;

  25.    wake_up_interruptible(&r_read); //就是这里

  26.    return ret;

  27. }
阅读(1610) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~