您的位置:首页 > 游戏 > 手游 > 中国最新消息最新疫情_网络营销推广系统排名推荐系统_澳门seo推广_产品如何做线上推广

中国最新消息最新疫情_网络营销推广系统排名推荐系统_澳门seo推广_产品如何做线上推广

2025/7/1 11:57:17 来源:https://blog.csdn.net/CATTLE_L/article/details/147046164  浏览:    关键词:中国最新消息最新疫情_网络营销推广系统排名推荐系统_澳门seo推广_产品如何做线上推广
中国最新消息最新疫情_网络营销推广系统排名推荐系统_澳门seo推广_产品如何做线上推广

文章目录

  • 1、前言
  • 2、阻塞与非阻塞IO
    • 2.1、阻塞方式
    • 2.2、非阻塞方式
    • 2.3、小结
  • 3、异步IO
    • 3.1、poll
    • 3.2、select
    • 3.3、epoll
    • 3.4、poll和epoll示例比较
    • 3.5、异步通知
  • 4、unlocked_ioctl
  • 5、sysfs_notify

1、前言

  1. 学习参考书籍以及本文涉及的示例程序:李山文的《Linux驱动开发进阶》
  2. 本文属于个人学习后的总结,不太具备教学功能。

2、阻塞与非阻塞IO

2.1、阻塞方式

用户程序调用read系统调用时,从用户态切换到内核态。内核检查设备是否准备好数据,如果设备尚未准备好数据,内核会将当前进程标记为“阻塞”状态,并将其放入等待队列中,同时进入休眠状态。当设备准备好数据时,内核会将等待队列中的进程唤醒。内核从设备读取数据,并将数据复制到用户空间。系统调用返回,用户程序继续执行。

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/block_io

重点宏或函数如下:

init_waitqueue_head(wq_head)
wait_event_interruptible(wq_head, condition)
wake_up_interruptible(x)

2.2、非阻塞方式

非阻塞方式和阻塞方式相比,当用户程序调用read系统调用时,如果设备尚未准备好数据,直接返回错误。此时可以继续发起read系统调用。

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/nonblokck-io

2.3、小结

所以阻塞方式不会占用cpu资源,适合对实时性不高的场景。非阻塞方式需要不断轮询,可能会增加cpu负载,适合高并发场景。

3、异步IO

3.1、poll

poll可以说是对阻塞IO的一种改进。我们知道阻塞IO中,如果设备状态一直不可用,那么应用程序会一直休眠。而poll机制中,就是增加了超时机制。当一段时间内设备还是不可用,则强行调度,将应用程序唤醒。

作为驱动开发者,需要实现poll驱动的回调函数。

static __poll_t key_poll(struct file *file, poll_table *wait)
{poll_wait(file, &key->wait_head, wait);if (key->ev_press == 1)return EPOLLIN | EPOLLRDNORM;return EPOLLOUT | EPOLLWRNORM;
}static struct file_operations key_ops = {....poll = key_poll,...
};

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/poll

3.2、select

poll机制和select机制是一样的,应用程序调用select系统调用时,最终调用的还是内核驱动程序中的poll函数。所以主要了解应用程序中的select系统调用即可。

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/select

3.3、epoll

当fd数量小于1000时,使用poll和select还算合适。因为poll和select每次调用时都需要遍历所有监听的fd,检查他们的就绪状态,例如,监听10000个fd,即使只有1个fd就绪,也需要遍历全部10000个,效率极低。

而epoll适用于有大量的描述符需要同时轮询,并且这些连接最好是长连接。用户空间的应用程序调用epoll相关接口,最终还是调用内核的poll接口。

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/epoll

3.4、poll和epoll示例比较

poll的低效实现:

// 每次需遍历所有 FD
struct pollfd fds[10000];
while (1) {int ret = poll(fds, 10000, 1000);  // O(n) 遍历for (int i = 0; i < 10000; i++) {  // 再次遍历检查if (fds[i].revents & POLLIN) {// 处理就绪 FD}}
}

epoll的高效实现:

int epfd = epoll_create1(0);
struct epoll_event ev, events[100];// 注册 FD(首次拷贝到内核)
ev.events = EPOLLIN | EPOLLET;  // ET 模式
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);while (1) {int nready = epoll_wait(epfd, events, 100, 1000);  // 仅返回就绪 FDfor (int i = 0; i < nready; i++) {                 // 直接处理// 处理 events[i].data.fd}
}

epoll是Linux特有的,注意跨平台限制。

3.5、异步通知

上面介绍的poll/select、epoll还是需要主动去查询设备是否可用,大多数情况下,设备都是不可用的。所以是否还有更好的方式,那就是异步通知,当设备可用时,内核驱动程序主动向应用程序发起通知。

可以参考以前写的:I/O管理:异步通知

同时相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/async

4、unlocked_ioctl

ioctl是旧版本的内核API,需要持有大内核锁。unlocked_ioctl是现代内核中推荐使用的API,它不需要持有大内核锁,从而提高了性能和灵活性。

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/ioctl

5、sysfs_notify

当用户空间使用poll、select、epoll接口检测一个sysfs目录下的属性文件时,此时如果内核不做任何动作,则用户空间中的进程就会被阻塞起来,当内核中调用sysfs_notify函数时,此时用户空间的进程被唤醒,就可以执行相应的动作。

sysfs_notify函数实现如下:

最终会调用kernfs_notify(),最终调用wake_up_interruptible:

相关示例程序可以参考:https://gitee.com/li-shan-asked/linux-advanced-development-code/tree/master/part5/sysfs_notify

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com