美文网首页
Contiki memb

Contiki memb

作者: LittleEndian | 来源:发表于2018-08-08 23:30 被阅读0次

    Contiki提供了三种内存分配机制:memb机制、mmem机制和标准C语言库中的堆内存分配机制。memb最常使用,mmem极少使用,而使用堆内存分配是一件危险的事情。这篇日志讲解memb

    memb库提供了一系列内存块管理函数。内存块在静态内存区中被分配为具有固定尺寸的数组。
    先把里面的例子搬出来

     #include "contiki.h"
     #include "lib/memb.h"
    
    struct connection {
       int socket;
     };
     MEMB(connections, struct connection, 16);
    
    struct connection *
    open_connection(int socket)
     {
       struct connection *conn;
    
       conn = memb_alloc(&connections);
       if(conn == NULL) {
         return NULL;
       }
       conn->socket = socket;
       return conn;
     }
    
     void
     close_connection(struct connection *conn)
     {
       memb_free(&connections, conn);
     }
    

    先来看看MEMB()宏源码:

    #define MEMB(name, structure, num)\ 
            static char CC_CONCAT(name,_memb_count)[num]; \
            static structure CC_CONCAT(name,_memb_mem)[num]; \
            static struct memb name = {sizeof(structure), num, \
                            CC_CONCAT(name,_memb_count), \
                            (void *) CC_CONCAT(name,_memb_mem)}
    struct memb {
        unsigned short size;
        //num表示可以存放的结构体个数,由于用short声明,表明最多只能控制127个结构体
        unsigned short num;
        char *count;
        void *mem;
    };
    

    先借用上例中的代码把这个宏展开来看看:

    struct connection {
       int socket;
     };
     MEMB(connections, struct connection, 16);
    
    

    展开后的代码:

    //char数组,估计用于指向实际内存地址 
    static char connections_memb_count[16];
    //结构体数组,结构体实际存放的地方 
    static struct connection connections_memb_mem[16];
    static struct memb connections =
    {
      sizeof(struct connection), //这里可以假设为2,一个int的大小 
      16, //结构体总个数 
      connections_memb_count, //指向指针数组
      (void *)connections_memb_mem //指向结构体实际存放的地方
     }
    

    这个东西讲出来挺拗口,来张图就一目了然了:

    内存分配---memb

    小结一下:有一个结构体connection,我们需要分配一段内存存放16个connection。使用MEMB实际上已经分配了这16个空间了,需要注意的是static关键字表明,它们被分配到了静态内存区。那么现在还有一个疑问,connections_memb_count[16]里面存放什么东西?有何用,得继续往下研究。

    下面来看下memb_init原型:

    void memb_init(struct memb *m)
    { 
      //把char数组里面的元素全部初始化为0
      memset(m->count, 0, m->num);
      //把结构体所占内存全部初始化为0    
      memset(m->mem, 0, m->size * m->num);
    }
    

    memset()函数是C语言标准库函数,memb_init函数就是把所占内存全部清0。

    memb_alloc原型:

    void *memb_alloc(struct memb *m)
    {
          int i;
          for(i = 0; i < m->num; ++i)
          {
                if(m->count[i] == 0)   //为0表示此空间并未使用
               {
                      ++(m->count[i]); //等同于m->count[i]=1;                  
                 //返回分配的结构体空间首地址                  
                 return (void *)((char *)m->mem + (i * m->size));
                }
          }
          /* 能走到这里说明没有多余空间,分配失败了,标志为返回NULL */
          return NULL;
    }
    

    现在终于明白connections_memb_count[16]的作用了,可以把它理解为标志位。某段结构体空间已用则标上1,某段结构体空间空闲则标上0。如果象C#那样有BitArray这样的数据结构,完全可以用一个位来存放这样的标志,现在用8个位存放一个标志,有点浪费空间了。不过如果用位运算,访问的时候需要另外声明函数返回标志,有些麻烦。

    char[16]实际上和struct[16]一一对应,在char[16]中只要找到一个为0的元素,就说明它所对应的struct空间空闲,这时返回struct空间首地址作为memb_alloc函数的返回值。

    memb_free原型:

    char memb_free(struct memb *m, void *ptr)
    {
          int i;
          char *ptr2;
          ptr2 = (char *)m->mem;
          for(i = 0; i < m->num; ++i)
          {
                if(ptr2 == (char *)ptr)   //找到释放的空间             
                {
                      if(m->count[i] > 0)
                      {
                            --(m->count[i]); //设标志位为0 
                     }
                      return m->count[i]; //返回0             
                }
                ptr2 += m->size; //指向下一块空间      
          }
          return -1; //没找到相应空间返回-1 
    }
    
    

    memb_free用于释放空间,实际上只是把相应的标志位设为0,结构体空间原来的数据并未清除,这是不是有些危险?所以在使用memb的时候一定要注意,里面的结构体每个成员在使用前必须要全部赋值,否则会有出错的可能。

    **int memb_inmemb(struct memb m, void ptr)

    求证一个指针是否在memb之中

    *int memb_numfree(struct memb m)

    返回memb的空余空间的个数

    最后来个总结吧,memb这东西我个人感觉更象是一个线程池之类的东西。例如我们在写程序时,需要多次同时用到一个结构体类型,每个结构体每次用的时间都不确定,这篇文章开头用的socket就是个很典型的例子。这时就可以使用memb进行统一管理。memb的作用可以作个比喻:学校有个体育馆,里面有6个羽毛球场地,学生要打羽毛球就必须到体育馆去,打完球后,空出来的场地可以让别的同学继续打,如果没有场地了则必须等到有人打完后才能轮到你。

    相关文章

      网友评论

          本文标题:Contiki memb

          本文链接:https://www.haomeiwen.com/subject/eppfbftx.html