等待队列(使用篇)

I/O的阻塞操作与等待队列

1,基本概念

什么是阻塞操作?

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

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

                  


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

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

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

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

 2,实例

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

 

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

1) 该设备的结构体

[cpp]  view plain copy
  1. structmyfifo_dev  
  2. {  
  3.      /*其他成员这里就不列出了*/  
  4.   
  5. wait_queue_head_t   r_write;   // 阻塞写的等待队列头  
  6. wait_queue_head_t   r_read;    // 阻塞读的等待队列头  
  7.   
  8. };  

2) 等待队列的初始化  

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

问1:在哪里初始化呢?   

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

问2: 怎么初始化?

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

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

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

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

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

[cpp]  view plain copy
  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.   
  6.     if(down_interruptible(&sem) )  
  7.         return-ERESTARTSYS;  
  8.   
  9.     flag= 0;  
  10.     if(copy_to_user(buf,data,len) )  
  11.     {  
  12.         up(&sem);  
  13.         return-EFAULT;  
  14.     }  
  15.     up(&sem);  
  16.     returnlen;  
  17. }  

4) 将一个进程从等待队列移出(唤醒)

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

[cpp]  view plain copy
  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.   
  10.    if (count > 127)  
  11.        return -ENOMEM;  
  12.   
  13.    if (count < 0)  
  14.        return -EINVAL;  
  15.   
  16.    if (copy_from_user(data, buf, count))  
  17.    {  
  18.        up(&sem);  
  19.        return -EFAULT;  
  20.    }  
  21.    else {  
  22.        data[127] = '\0';  
  23.        pr_info("kernel received: %s\n", data);  
  24.        ret = count;  
  25.   
  26.    }  
  27.   
  28.    up(&sem);  
  29.   
  30.    flag = 1;  
  31.   
  32.    wake_up_interruptible(&r_read); //就是这里  
  33.   
  34.    return ret;  
  35.   
  36. }  


新手学习有啥不对的地方,欢迎砸板砖! 谢谢~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值