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

怎么改网站上的logo/今日国际新闻最新消息事件

怎么改网站上的logo,今日国际新闻最新消息事件,wordpress循环所有文章,网站建设任务和标准内核中的队列是以字节形式保存数据的&#xff0c;所以获取数据的时候&#xff0c;需要知道数据的大小。 如果从队列中取得数据时指定的大小不对的话&#xff0c;取得数据会不完整或过大。 内核中关于队列定义的头文件位于&#xff1a;<linux/kfifo.h> include/linux/kf…

内核中的队列是以字节形式保存数据的,所以获取数据的时候,需要知道数据的大小。

如果从队列中取得数据时指定的大小不对的话,取得数据会不完整或过大。

内核中关于队列定义的头文件位于:<linux/kfifo.h> include/linux/kfifo.h

头文件中定义的函数的实现位于:kernel/kfifo.c

内核队列编程需要注意的是:

队列的size在初始化时,始终设定为2的n次方
使用队列之前将队列结构体中的锁(spinlock)释放
1. kfifo概述

        kfifo 是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现;它提供一个无边界的字节流服务,最重要的一点是,它使用并行无锁编程技术,即当它用于只有一个入队线程和一个出队线程的场情时,两个线程可以并发操作,而不需要任何加锁行为,就可以保证kfifo的线程安全。
 

 struct kfifo {  unsignedchar *buffer;    /* the buffer holdingthe data */  unsignedint size;    /* the size of the allocatedbuffer */  unsignedint in;    /* data is added at offset (in% size) */  unsignedint out;    /* data is extracted fromoff. (out % size) */  spinlock_t*lock;    /* protects concurrentmodifications */  };  

      这是kfifo的数据结构,kfifo主要提供了两个操作,__kfifo_put(入队操作)和__kfifo_get(出队操作)。 它的各个数据成员如下:
buffer, 用于存放数据的缓存

size,      buffer空间的大小,在初化时,将它向上扩展成2的幂

lock,      如果使用不能保证任何时间最多只有一个读线程和写线程,需要使用该lock实施同步。

in, out,  和buffer一起构成一个循环队列。 in指向buffer中队尾,而且out指向buffer中的队头,in是数据被开始存放的偏移位置,out是队列开始取出数据的偏移位置。它的结构如示图如下:

+--------------------------------------------------------------+
|           |<----------data---------->|                                   | 
+--------------------------------------------------------------+ 
           ^                                      ^  
            |                                       | 
            out                                   in

在put和get函数中堆in,out做了很巧妙的处理!

2. kfifo_alloc 分配kfifo内存和初始化工作 
 

 struct kfifo*kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)  {  unsignedchar *buffer;  structkfifo *ret;  /* * round upto the next power of 2, since our 'let the indices * wrap'tachnique works only in this case. */  if (size& (size - 1)) {  BUG_ON(size > 0x80000000);  size = roundup_pow_of_two(size);  }  buffer =kmalloc(size, gfp_mask);  if(!buffer) returnERR_PTR(-ENOMEM);  ret =kfifo_init(buffer, size, gfp_mask, lock);  if (IS_ERR(ret))  kfree(buffer);       returnret;  }   

      这里值得一提的是,kfifo->size的值总是在调用者传进来的size参数的基础上向2的幂扩展,这是内核一贯的做法。这样的好处不言而喻--对kfifo->size取模运算可以转化为与运算,如下:

kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1)

     在kfifo_alloc函数中,使用size & (size – 1)来判断size 是否为2幂,如果条件为真,则表示size不是2的幂,然后调用roundup_pow_of_two将之向上扩展为2的幂。在kfifo_alloc函 数中看到调用了kfifo_init函数: 
 

/**30  * kfifo_init - allocates a new FIFO using apreallocated buffer31  * @buffer: the preallocated buffer to beused.32  * @size: the size of the internal buffer,this have to be a power of 2.33  * @gfp_mask: get_free_pages mask, passed tokmalloc()34  * @lock: the lock to be used to protect thefifo buffer35  *36  * Do NOT pass the kfifo to kfifo_free() afteruse! Simply free the37  * &struct kfifo with kfree().38  */39 struct kfifo*kfifo_init(unsigned char *buffer, unsigned int size,40              gfp_t gfp_mask, spinlock_t *lock)41 {42     struct kfifo *fifo;43
44     /* size must be a power of 2 */45     BUG_ON(!is_power_of_2(size));4647     fifo = kmalloc(sizeof(struct kfifo),gfp_mask);48     if (!fifo)49         return ERR_PTR(-ENOMEM);5051     fifo->buffer = buffer;52     fifo->size = size;53     fifo->in = fifo->out = 0;54     fifo->lock = lock;5556     return fifo;57 }

3. __kfifo_put和__kfifo_get,巧妙的入队和出队操作,无锁并发

__kfifo_put是入队操作,它先将数据放入buffer里面,最后才修改in参数;__kfifo_get是出队操作,它先将数据从buffer中移走,最后才修改out。你会发现in和out两者各司其职。
 

  unsigned int__kfifo_put(struct kfifo *fifo,  unsigned char *buffer, unsigned int len)  {  unsignedint l;  len =min(len, fifo->size - fifo->in + fifo->out);       /* * Ensurethat we sample the fifo->out index -before- we * startputting bytes into the kfifo. */  smp_mb();  /* firstput the data starting from fifo->in to buffer end */  l =min(len, fifo->size - (fifo->in & (fifo->size - 1)));  memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)),buffer, l);   /* then putthe rest (if any) at the beginning of the buffer */  memcpy(fifo->buffer, buffer + l, len - l);     /* * Ensurethat we add the bytes to the kfifo -before- * weupdate the fifo->in index. */      smp_wmb();       fifo->in+= len;   //每次累加,到达最大值后溢出,自动转为0   returnlen;   } unsigned int__kfifo_get(struct kfifo *fifo,  unsigned char *buffer, unsigned int len)  {  unsignedint l;  len =min(len, fifo->in - fifo->out);  /* * Ensurethat we sample the fifo->in index -before- we * startremoving bytes from the kfifo. */  smp_rmb();       /* firstget the data from fifo->out until the end of the buffer */  l =min(len, fifo->size - (fifo->out & (fifo->size - 1)));  memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);      /* then getthe rest (if any) from the beginning of the buffer */  memcpy(buffer + l, fifo->buffer, len - l);  /* * Ensurethat we remove the bytes from the kfifo -before- * weupdate the fifo->out index. */       smp_mb();       fifo->out += len;   //每次累加,到达最大值后溢出,自动转为0     returnlen;  }   

        从上面的代码发现,put和get是非常精简的,下面分情况讨论函数的执行过程:

        队列的队头队尾下标不受队列长度的限制,就算队头下标大于队列长度,也一样可以使用,原理就在于,数据不是全部放在队头(fifo->out)和队尾(fifo->in)之间的内存空间,而是把超出队头队尾之间长度的数据放到整个队列buffer的开始处

1、入队操作    

         蓝色部分为真实数据所在内存段,白色部分其实为逻辑上假定的数据所在地,也就是说,为了给用户一种真正的队列感觉——从尾部推进数据,从头部拉取数据,那么就必须让fifo->out和fifo->in只能一直往一个方向推进,但是由于fifo所分配的buffer是有限的一段连续内存,fifo->out和fifo->in迟早要“越界”(这里的越界是in和out大于size,in和out是整数,是相对于buffer的偏移量), 入队列的操作,保证fifo->out和fifo->in是一直往右推进的。

        如果fifo->in小于buffer->size,那么先放完buffer->size-fifo->in这段内存空间,剩下的部分,转移到buffer的可用空间开头存放;如果fifo->in大于buffer->size,那么直接把要入队列的数据放到buffer可用空间开头。

     在put的函数中,有两次取值min和两次memcpy,

         情况1、如果fifo->in小于fifo->size,并且in和out都没有越界(都小于size)

         那么第一个min中的fifo->size-fifo->in+fifo->out是队列空余的空间大小(这里要求所存放的字符串长度小于队列空余大小)

         第二个min中的fifo->in &(fifo->size - 1)是in相对于buffer的偏移位置

         如果从in开始到队列末尾便可存放字符串,第一个min取len,第二个min取len,第一个memcpy是从buffer的in开始拷贝len个字符,第二个memcpy拷贝0个字符。

        如果从in开始到队列末尾不能存放所有的字符,第一个min取值为len,第二个min取值fifo->size- (fifo->in & (fifo->size - 1)),也就是从in到队列末尾的大小;第一个memcpy是讲队列从in开始到队列末尾填充满,填充的长度也就是l,第二个memcpy是从队列开始填充剩余的len-l长度的字符串。

          in累加len的长度,in一直累加,这也是一个巧妙之处,是利用了unsigned int 的回环。

  情况2、如果fifo->in小于fifo->size, out没有越界,in超过了size

          如果in一旦超多size,那么队列的开头一定存放了数据,并且队列末尾没有空余,将数据存放到对垒开始的地方。

          那么第一个min中的fifo->size-fifo->in+fifo->out是队列空余的空间大小

          第二个min中的fifo->in& (fifo->size - 1)是in相对于buffer的偏移位置 

          这个时候fifo->in > fifo->out,但是fifo->in & (fifo->size - 1)  < fifo->out

         此时需要从队列的开始存放数据,第一个min取len,第二个min取len,因为此时fifo->size- (fifo->in & (fifo->size - 1))肯定小于fifo->size-fifo->in+fifo->out;第一个memcpy是从队列开头的in存放len的字节,第二个memcpy不拷贝字节。

       情况3、如果fifo->in小于fifo->size, out没有越界,in和out都超过了size

         这种情况的复制情况和上面一样,都是第一次直接拷贝结束。

        分析,因为我们只考虑了放,没有考虑取,在取的过程也是Out一直累加,如果累加到超过了unsigned  int,那么又从0开始赋值。同时里面关于in和out的操作都是和size取模运算,所以in和out都会在size范围内。这也是笼统的理解,但是这个理解是正确的。

        在put的过程中,只要字符串长度小于队列空余空间大小,in和Out无论从数值上怎么越界,第一个min取值为len,第二个min中的fifo->size- (fifo->in & (fifo->size - 1))一定是从in偏移量开始到队列末尾的空余大小,这个值和len相比较,取其中较小者,换句话说,如果从in开始到队列末尾的空余空间长度大于字符串长度,那么第一个memcpy搞定一切,第二个memcpy不再从buffer的头部开始复制数据;如果从in开始到队列末尾的空余空间大小小于字符串长度,那么从in开始的空间先复制满,然后从空开始复制剩余的字符。无论哪种情况都是这个过程。

    2、对于get函数

      情况1:fifo->in大于fifo->size而fifo->out小于fifo->size(即只有fifo->in“越界”),则先读取fifo->out到fifo->size-1的那一段,大小为l个byte,然后再读取剩下的从buffer开头,大小为len-l个byte的数据(如下图所示,即先读data A段, 再读出data B段);

       情况2:fifo->in和fifo->out都“越界”了,那么l = min(len, fifo->size - (fifo->out & (fifo->size -1))); 这一语句便起作用了,此时fifo->out&fifo->size-1的结果即实际要读的数据所在的内存地址相对于buffer起始地址的偏移值(如下图所示,左边为实际上存在于内存中的data A段, 而右边虚线框为逻辑上的data A段的位置);

        分析:对于get的情况, 假设整个过程中fifo->in> fifo->out始终成立,并且假设get的字符串长度始终小于队列总数据的长度,第一个min的取值为min。第二个min中的fifo->size - (fifo->out & (fifo->size - 1))表示从out到队列末尾的字符串长度,如果这段字符串的长度大于len,那么第一个memcpy直接拷贝所要获取的字符串长度,第二个不拷贝,如果小于len的长度,从out开始拷贝到结束,然后从队列的开始拷贝剩余的字符串。 

http://www.jmfq.cn/news/4804993.html

相关文章:

  • 做一个动态网站多少钱/百度搜索推广怎么做
  • wordpress网站日志/西安网络公司
  • 深圳物流公司大全排名/淘宝seo是什么意思
  • l凉州区城乡建设部网站首页/网络推广软文
  • 临安市建设局门户网站/seo网络贸易网站推广
  • 除了做视频网站还能做什么网站/qq群推广引流免费网站
  • 网站做百度地图定位/如何去推广一个app
  • 百度下拉框推广网站/中文搜索引擎大全
  • 网站建设要域名和什么/设计公司网站设计
  • 链家网的网站开发费用大概多少钱/宣传推广的十种方式
  • 万网网站建设步骤/优云优客百度推广效果怎么样
  • 平顶山市做网站/班级优化大师功能介绍
  • 做电影网站失败了/网站推广服务报价表
  • 大沥网站建设制作/济南网站建设老威
  • 临沂市建设局兰山区网站/全网推广平台有哪些
  • 河北辛集住房和城乡建设厅网站/百度一下你就知道了
  • 吃的网站要怎么做/电商平台排行榜前十名
  • wordpress经验/广州网站优化
  • 专门做旅游攻略的网站有哪些/公众号seo排名优化
  • 做软件贵还是做网站贵/google关键词挖掘工具
  • 公司做网站 微信平台/百度爱采购推广平台
  • 自己做网站要不要钱/广州推广服务
  • 动态网站开发代码/百度如何搜索关键词
  • 网站的ftp怎么登陆/湖南seo快速排名
  • 广西网站建设/品牌宣传文案范文
  • 找人建设一个网站多少钱/新东方培训机构官网
  • 上海招聘网站建设/搜索引擎关键词怎么优化
  • 宝安做网站公司/邢台网站公司
  • 济南 域名注册 网站建设/百度登陆
  • 网站空间pdf下载不了/手机优化器