当前位置: 首页 > news >正文

做网站文字编辑累吗赶集网网站建设费用

做网站文字编辑累吗,赶集网网站建设费用,手机必备软件100个,什么是网站栏目标题转载一篇文章#xff0c;讲解select和poll机制的#xff0c;分享给大家。前言Read the fucking source code! --By 鲁迅A picture is worth a thousand words. --By 高尔基1. 概述Linux系统在访问设备的时候#xff0c;存在以下几种IO模型#xff1a;Blocking IO Model讲解select和poll机制的分享给大家。前言Read the fucking source code!  --By 鲁迅A picture is worth a thousand words. --By 高尔基1. 概述Linux系统在访问设备的时候存在以下几种IO模型Blocking IO Model阻塞IO模型Nonblocking I/O Model非阻塞IO模型I/O Multiplexing ModelIO多路复用模型;Signal Driven I/O Model信号驱动IO模型Asynchronous I/O Model异步IO模型今天我们来分析下IO多路复用机制在Linux中是通过select/poll/epoll机制来实现的。先看一下阻塞IO模型与非阻塞IO模型的特点阻塞IO模型在IO访问的时候如果条件没有满足会将当前任务切换出去等到条件满足时再切换回来。缺点阻塞IO操作会让处于同一个线程的执行逻辑都在阻塞期间无法执行这往往意味着需要创建单独的线程来交互。非阻塞IO模型在IO访问的时候如果条件没有满足直接返回不会block该任务的后续操作。缺点非阻塞IO需要用户一直轮询操作轮询可能会来带CPU的占用问题。对单个设备IO操作时问题并不严重如果有多个设备呢比如在服务器中监听多个Client的收发处理这时候IO多路复用就显得尤为重要了来张图如果这个图让你有点迷惑那就像个男人一样man一下select/poll函数吧select:poll简单来说select/poll能监听多个设备的文件描述符只要有任何一个设备满足条件select/poll就会返回否则将进行睡眠等待。看起来select/poll像是一个管家了统一负责来监听处理了。已经迫不及待来看看原理了由于底层的机制大体差不多我将选择select来做进一步分析。2. 原理2.1 select系统调用从select的系统调用开始select系统调用最终的核心逻辑是在do_select函数中处理的参考fs/select.c文件do_select函数中有几个关键的操作初始化poll_wqueues结构包括几个关键函数指针的初始化用于驱动中进行回调处理循环遍历监测的文件描述符并且调用f_op-poll()函数如果有监测条件满足则会跳出循环在监测的文件描述符都不满足条件时poll_schedule_timeout让当前进程进行睡眠超时唤醒或者被所属的等待队列唤醒do_select函数的循环退出条件有三个检测的文件描述符满足条件超时有信号要处理在设备驱动程序中实现的poll()函数会在do_select()中被调用而驱动中的poll()函数需要调用poll_wait()函数poll_wait函数本身很简单就是去回调函数p-_qproc()这个回调函数正是poll_initwait()函数中初始化的__pollwait()所以来看看__pollwait()函数喽。2.2 __pollwait驱动中的poll_wait函数回调__pollwait这个函数完成的工作是向struct poll_wqueue结构中添加一条poll_table_entrypoll_table_entry中包含了等待队列的相关数据结构对等待队列的相关数据结构进行初始化包括设置等待队列唤醒时的回调函数指针设置成pollwake将任务添加到驱动程序中的等待队列中最终驱动可以通过wake_up_interruptile等接口来唤醒处理这一顿操作其实就是驱动向select维护的struct poll_wqueue中注册并将调用select的任务添加到驱动的等待队列中以便在合适的时机进行唤醒。所以本质上来说这是基于等待队列的机制来实现的。是不是还有点抽象来看看数据结构的组织关系吧。2.3 数据结构关系调用select系统调用的进程/线程会维护一个struct poll_wqueues结构其中两个关键字段pll_table该结构体中的函数指针_qproc指向__pollwait函数struct poll_table_entry[]存放不同设备的poll_table_entry这些条目的增加是在驱动调用poll_wait-__pollwait()时进行初始化并完成添加的2.4 驱动编写启示如果驱动中要支持select的接口调用那么需要做哪些事情呢如果理解了上文中的内容你会毫不犹豫的大声说出以下几条定义一个等待队列头wait_queue_head_t用于收留等待队列任务struct file_operations结构体中的poll函数需要实现比如xxx_poll()xxx_poll()函数中当然不要忘了poll_wait函数的调用了此外该函数的返回值mask需要注意是在条件满足时对应的值比如EPOLLIN/EPOLL/EPOLLERR等这个返回值是在do_select()函数中会去判断处理的条件满足的时候wake_up_interruptible唤醒任务当然也可以使用wake_up区别是wake_up_interruptible只能唤醒处于TASK_INTERRUPTIBLE状态的任务而wake_up能唤醒处于TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE状态的任务2.5 select/poll的差异select与poll本质上基本类似其中select是由BSD UNIX引入poll由SystemV引入select与poll需要轮询文件描述符集合并在用户态和内核态之间进行拷贝在文件描述符很多的情况下开销会比较大select默认支持的文件描述符数量是1024Linux提供了epoll机制改进了select与poll在效率与资源上的缺点未深入了解3. 示例代码3.1 内核驱动示例代码中的逻辑驱动维护一个count值当count值大于0时表明条件满足poll返回正常的mask值poll函数每执行一次count值就减去一次count的值可以由用户通过ioctl来进行设置#include linux/init.h #include linux/module.h #include linux/poll.h #include linux/wait.h #include linux/cdev.h #include linux/mutex.h #include linux/slab.h #include asm/ioctl.h#define POLL_DEV_NAME poll#define POLL_MAGIC P #define POLL_SET_COUNT (_IOW(POLL_MAGIC, 0, unsigned int))struct poll_dev {struct cdev cdev;struct class *class;struct device *device;wait_queue_head_t wq_head;struct mutex poll_mutex;unsigned int count;dev_t devno; };struct poll_dev *g_poll_dev NULL;static int poll_open(struct inode *inode, struct file *filp) {filp-private_data g_poll_dev;return 0; }static int poll_close(struct inode *inode, struct file *filp) {return 0; }static unsigned int poll_poll(struct file *filp, struct poll_table_struct *wait) {unsigned int mask 0;struct poll_dev *dev filp-private_data;mutex_lock(dev-poll_mutex);poll_wait(filp, dev-wq_head, wait);if (dev-count 0) {mask | POLLIN | POLLRDNORM;/* decrease each time */dev-count--;}mutex_unlock(dev-poll_mutex);return mask; }static long poll_ioctl(struct file *filp, unsigned int cmd,unsigned long arg) {struct poll_dev *dev filp-private_data;unsigned int cnt;switch (cmd) {case POLL_SET_COUNT:mutex_lock(dev-poll_mutex);if (copy_from_user(cnt, (void __user *)arg, _IOC_SIZE(cmd))) {pr_err(copy_from_user fail:%d\n, __LINE__);return -EFAULT;}if (dev-count 0) {wake_up_interruptible(dev-wq_head);}/* update count */dev-count cnt;mutex_unlock(dev-poll_mutex);break;default:return -EINVAL;}return 0; }static struct file_operations poll_fops {.owner THIS_MODULE,.open poll_open,.release poll_close,.poll poll_poll,.unlocked_ioctl poll_ioctl,.compat_ioctl poll_ioctl, };static int __init poll_init(void) {int ret;if (g_poll_dev NULL) {g_poll_dev (struct poll_dev *)kzalloc(sizeof(struct poll_dev), GFP_KERNEL);if (g_poll_dev NULL) {pr_err(struct poll_dev allocate fail\n);return -1;}}/* allocate device number */ret alloc_chrdev_region(g_poll_dev-devno, 0, 1, POLL_DEV_NAME);if (ret 0) {pr_err(alloc_chrdev_region fail:%d\n, ret);goto alloc_chrdev_err;}/* set char-device */cdev_init(g_poll_dev-cdev, poll_fops);g_poll_dev-cdev.owner THIS_MODULE;ret cdev_add(g_poll_dev-cdev, g_poll_dev-devno, 1);if (ret 0) {pr_err(cdev_add fail:%d\n, ret);goto cdev_add_err;}/* create device */g_poll_dev-class class_create(THIS_MODULE, POLL_DEV_NAME);if (IS_ERR(g_poll_dev-class)) {pr_err(class_create fail\n);goto class_create_err;}g_poll_dev-device device_create(g_poll_dev-class, NULL,g_poll_dev-devno, NULL, POLL_DEV_NAME);if (IS_ERR(g_poll_dev-device)) {pr_err(device_create fail\n);goto device_create_err;}mutex_init(g_poll_dev-poll_mutex);init_waitqueue_head(g_poll_dev-wq_head);return 0;device_create_err:class_destroy(g_poll_dev-class); class_create_err:cdev_del(g_poll_dev-cdev); cdev_add_err:unregister_chrdev_region(g_poll_dev-devno, 1); alloc_chrdev_err:kfree(g_poll_dev);g_poll_dev NULL;return -1; }static void __exit poll_exit(void) {cdev_del(g_poll_dev-cdev);device_destroy(g_poll_dev-class, g_poll_dev-devno);unregister_chrdev_region(g_poll_dev-devno, 1);class_destroy(g_poll_dev-class);kfree(g_poll_dev);g_poll_dev NULL; }module_init(poll_init); module_exit(poll_exit);MODULE_DESCRIPTION(select/poll test); MODULE_AUTHOR(LoyenWang); MODULE_LICENSE(GPL); 3.2 测试代码测试代码逻辑创建一个设值线程用于每隔2秒来设置一次count值主线程调用select函数监听当设值线程设置了count值后select便会返回#include stdio.h #include string.h #include fcntl.h #include pthread.h #include errno.h #include unistd.h #include sys/ioctl.h #include sys/stat.h #include sys/types.h #include sys/time.hstatic void *set_count_thread(void *arg) {int fd *(int *)arg;unsigned int count_value 1;int loop_cnt 20;int ret;while (loop_cnt--) {ret ioctl(fd, NOTIFY_SET_COUNT, count_value);if (ret 0) {printf(ioctl set count value fail:%s\n, strerror(errno));return NULL;}sleep(1);}return NULL; }int main(void) {int fd;int ret;pthread_t setcnt_tid;int loop_cnt 20;/* for select use */fd_set rfds;struct timeval tv;fd open(/dev/poll, O_RDWR);if (fd 0) {printf(/dev/poll open failed: %s\n, strerror(errno));return -1;}/* wait up to five seconds */tv.tv_sec 5;tv.tv_usec 0;ret pthread_create(setcnt_tid, NULL,set_count_thread, fd);if (ret 0) {printf(set_count_thread create fail: %d\n, ret);return -1;}while (loop_cnt--) {FD_ZERO(rfds);FD_SET(fd, rfds);ret select(fd 1, rfds, NULL, NULL, tv);//ret select(fd 1, rfds, NULL, NULL, NULL);if (ret -1) {perror(select());break;}else if (ret)printf(Data is available now.\n);else {printf(No data within five seconds.\n);}}ret pthread_join(setcnt_tid, NULL);if (ret 0) {printf(set_count_thread join fail.\n);return -1;}close(fd);return 0; } 推荐阅读专辑|Linux文章汇总专辑|程序人生嵌入式Linux微信扫描二维码关注我的公众号
http://www.zqtcl.cn/news/218801/

相关文章:

  • 济南建设银行网站应用制作app软件
  • 网站开发实习个人小结关于做展厅的网站
  • 网站设计三把火如何制作动漫网站模板
  • 重庆做网站 哪个好些嘛开通qq空间申请网址
  • 制作网站 太原买的电脑没有wordpress
  • 图书馆建设投稿网站可信网站认证logo
  • 专做阀门网站网站如何做银联在线支付
  • 南通网站seo网页制作图片轮播
  • 高端品牌网站建设哪家好中医网站模板
  • 怎么做多语言网站图片添加文字在线制作
  • js特效演示网站wordpress本地视频
  • 徐州做网站哪个好上海国际人才网
  • 黑龙江省城乡和住房建设厅网站首页公司营业执照查询
  • 锦州北京网站建设支付公司网站建设会计分录
  • 泉州做网站优化价格软件公众号开发
  • 商丘旅游网站的建设攀枝花城市建设网站
  • 网站主页设计素材一条龙做网站
  • 咖啡店网站首页怎么做163邮箱注册
  • 网站开发开源程序网站建设及推广销售话术
  • 门户网站和官网的区别美间在线设计平台
  • 淮南制作网站游戏代理哪个平台正规
  • seo网站推广软件 快排手机网页小游戏
  • 上海免费网站建设品牌长沙com建站网站设计
  • 大网站成本品牌设计风格
  • 电大形考任在哪个网站做湖南seo推广服务
  • dede网站 异步生成wordpress 页面新建
  • 郑州网站制作网页网站优化我自己可以做吗
  • 合肥做网站的公司百度做兼职去哪个网站
  • 重庆市城市建设规划官方网站一款app从开发到上线的流程
  • 微网站开发难吗登录qq网页版