阻塞 IO

进程的状态

在操作系统中,进程至少要有三种基本状态:运行状态,就绪状态和等待状态。
在这里插入图片描述
1)就绪——执行:对就绪状态的进程,当进程调度程序按一种选定的策略从中选中一个就绪进程,为之分配了处理机后,该进程便由就绪状态变为执行状态;
2)执行——等待:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为等待状态,如进程提出输入/输出请求而变成等待外部设备传输信息的状态,进程申请资源(主存空间或外部设备)得不到满足时变成等待资源状态,进程运行中出现了故障(程序出错或主存储器读写错等)变成等待干预状态等等;
3)等待——就绪:处于等待状态的进程,在其等待的事件已经发生,如输入/输出完成,资源得到满足或错误处理完毕时,处于等待状态的进程并不马上转入执行状态,而是先转入就绪状态,然后再由系统进程调度程序在适当的时候将该进程转为执行状态;
4)执行——就绪:正在执行的进程,因时间片用完而被暂停执行,或在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行而被迫让出处理机时,该进程便由执行状态转变为就绪状态。
直接改变进程状态方法:
__set_current_state(TASK_INTERRUPTIBLE)

In older code, you often see something like this instead:
1、current->state = TASK_INTERRUPTIBLE;
But changing current directly in that manner is discouraged;
2、schedule( );
The call to schedule is, of course, the way to invoke the scheduler and yield the CPU 。
注意:设置为 TASK_UNINTERRUPTIBLE 时,ctrl+c退不出来,使用的唤醒函数是wake_up,且如果收到过ctrl+c等信号,再被wake_up唤醒,会读/写出错返回。

阻塞与非阻塞I/O(sbh_158)

阻塞操作:在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。
非阻塞操作:在执行设备操作时若不能获得资源时并不挂起,它或者放弃,或者不停地查询直到可以进行操作为止。
在这里插入图片描述

等待队列

在Linux驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程时,将进程放入等待队列,当唤醒进程时,从等待等列中取出进程。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在许多设备驱动中,并不调用sleep_on()或者intertuptiple_sleep_on(),而是亲自进行进程状态的切换。

Q:前面我们跳过了一个重要的问题:当一个驱动无法立刻满足请求时应当如何处理? 例如:调用read时没有数据可读, 但以后可能会有;或者一个进程试图写设备,但是设备暂时没有准备好接收数据。应用程序通常不关心这种问题,应用程序只是调用 read 或 write 并得到返回值。
A:驱动程序应当(缺省地)阻塞进程,使它进入睡眠,直到请求可以得到满足。

阻塞操作

在阻塞型驱动程序中,read实现方式如下:
如果进程调用read,但没有数据或数据不足,进程阻塞。当数据到达时,进程被唤醒,并将数据返回给调用者。
在阻塞型驱动程序中,Write实现方式如下:
如果进程调用了write,但设备没有足够缓冲区,进程阻塞。当数据被读出设备后,缓冲区中空出部分空间,则唤醒进程。

非阻塞操作

阻塞是文件读写操作的默认选择,但应用程序员可人为设置读写操作为非阻塞方式,通过设置O_NONBLOCK标志,该标志定义在<linux/fcntl.h>中,在打开文件时指定。
如果设置了O_NONBLOCK标志,read和write的行为是不同的。如果进程在没有数据就绪时调用了read,或者在缓冲区没有空间时调用了write,系统只是简单地返回 -EAGAIN。

总结:

使用等待队列有3种方法:

1: 亲自进行进程状态的改变和切换。—4globalfifo
(项目中发现:多个进程在等待时,如等待读,如果另外一进程如写进程唤醒它们,则它们全醒,资源够几个被唤醒的进程使用则几个进程都能操作成功,剩下的操作不成功)

2: 使用wait_event_interruptible(dev->r_wait,flag_r!=0);需要设置flag_r。—例子4globalfifo_2
(项目中发现:多个进程在等待时,如等待读,如果另外一进程如写进程唤醒它们,则一个进程被唤醒并操作成功,剩下的继续休眠)

3: 使用interruptible_sleep_on(&dev->r_wait);—例子4globalfifo_2
(项目中发现:多个进程在等待时,如等待读,如果另外一进程如写进程唤醒它们,则它们全醒,资源够几个被唤醒的进程使用则几个进程都能操作成功,剩下的操作不成功)

Select系统调用(功能)

Select系统调用用于同时检测多个I/O设备,当没有设备准备好时,select将阻塞调用进程,其中任一设备准备好时,select返回。

int select(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, 
   const struct timeval *timeout)

在这里插入图片描述

设备驱动中的poll()

unsigned int(*poll)(struct file filp,struct poll_table wait);
参数wait 是轮询表指针。
此函数要完成2项工作:
1 调用poll_wait()函数,将等待队列头添加到poll_table
2 返回表示是否能对设备进行无阻塞读、写访问的掩码。
在这里插入图片描述

Poll返回值

POLLIN
This bit must be set if the device can be read without blocking.
POLLRDNORM
This bit must be set if “normal” data is available for reading. A readable device returns (POLLIN | POLLRDNORM).
POLLOUT
This bit is set in the return value if the device can be written to without blocking.
POLLWRNORM
This bit has the same meaning as POLLOUT, and sometimes it actually is the same number. A writable device returns (POLLOUT | POLLWRNORM).

工作原理

Poll方法只是做一个登记,真正的阻塞发生在select.c 中的 do_select函数,处理流程:
1:初始化 poll_table 表
2:依次调用每个文件的 poll 方法
3:poll 方法调用的 poll_wait会把当前的进程挂到驱动提供的wait_queue_head_t中
4:假如能读或能写或有信号,就返回5:否则调用 schedule_timeout 睡眠

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值