swoole源码学习——协程编号的管理和分配
来源:互联网 发布:手机软件广告拦截软件 编辑:程序博客网 时间:2024/06/07 11:51
swoole中定义了cidmap结构体用于管理和分配协程(coroutine)的编号,其定义位于swoole/swoole_coroutine.c 573行起
typedef struct cidmap
{
uint32_t nr_free; //nr_free表示剩余可用cid的数目,
char page[4096]; //共4096*8=32768个bit
} cidmap_t;
这里的nr_free表示剩余可用cid的数目。
而page[4096]则是因为一般在c语言中,一个char字符的大小为1字节也就是8个bit。
那么4096*8=32768 个bit,每个bit就代表其对应的编号有没有分配出去,0未分配,1已分配。
cidmap变量声明位于swoole/swoole_coroutine.c 579行起
从这里原有的注释中我们就可以得知,最多可分配的协程编号是32768个
/* 1 <= cid <= 32768 */
static cidmap_t cidmap = { 0x8000, {0} }; //0x8000代表16进制的8000,相当于10进制的32768
与cidmap相关的两个操作函数alloc_cidmap(分配编号) 和 free_cidmap(释放编号) 声明位于swoole/swoole_coroutine.c 29行起
static int alloc_cidmap(); //分配
static void free_cidmap(int cid); //释放
主要看一下alloc_cidmap函数,其实现位于swoole/swoole_coroutine.c 629行起
static int alloc_cidmap()
{
int cid;
if (cidmap.nr_free == 0) //检查是否还有未分配的协程编号
{
return -1;
}
cid = find_next_zero_bit(&cidmap.page, last_cid); //获取下一个值为0的bit(协程编号)
if (test_and_set_bit(cid, &cidmap.page)) //将标志位从0改成1
{
--cidmap.nr_free; //将未分配的协程编号数减一
last_cid = cid; //更换最后一个分配出去的cid为当前这个
return cid + 1;
}
return -1;
}
这里last_cid的初始值为-1。
函数的大致逻辑是首先检查是否还有可分配的协程编号,如有则找到最近的一个未分配的协程编号,然后将标识位置1,表示这个协程编号已被分配。
随后将cidmap结构体里的nr_free变量减一,将新获得的cid标记为最后分配出去的,最后返回cid加一的值
最关键的来了:find_next_zero_bit函数,此函数的作用是找到在page[4096]中下一个值为0的bit所对应的cid编号。
说实话,由于此函数使用了很多位操作,初看时让人一头雾水有点摸不着头脑,即使知道了每一行是在做什么位运算,也很难理解它这样做的原因:
/* find next free cid */
static int find_next_zero_bit(void *addr, int cid) //假设addr为0x28ef8,cid为-1
{
uint32_t *p;
uint32_t mask;
int mark = cid;//把传进来的cid先记下,mark等于-1
cid++;//cid自增1变成0
//0x7fff相当于二进制中的0111 1111 1111 1111,这里貌似是用来取绝对值(O__O)
//进行与操作后cid还是0
cid &= 0x7fff;
while (cid != mark)//cid(0)和mark(-1)相比较,两者不同时进入循环
{
//0x1f相当于10进制的31(1*16+15),2进制的0001 1111
//将cid保留后5位,然后将1U左移,mask为1
mask = 1U << (cid & 0x1f);
//将addr强制转成uint32_t型指针再加上cid右移5位后的值
//传入的addr为0x28ef8,则p为2682632
p = ((uint32_t*)addr) + (cid >> 5);
//将指针p指向的内容取反后和mask进行与操作
//-1&1 得1
if ((~(*p) & mask))
{
break; //跳出循环
}
++cid;
cid &= 0x7fff;
}
return cid; //返回cid其值为0
}
要理解这个函数,需要假象一个1024行,32列的内存表,如下图
函数中的(cid & 0x1f) 是取cid后五位的值(0~31),这个值代表这个cid在这个表中的列数
而(cid >> 5 )这一运算则是取cid前27位的值(cid由32位2进制表示),这个值代表这个cid在这个表中的行数。
阅读全文
0 0
- swoole源码学习——协程编号的管理和分配
- swoole源码学习——协程的概念,yield协程和原生协程的实现(上)
- Swoole源码学习记录(一)——进程间共享数据ShareMemory 和 MemoryPool
- Swoole源码学习记录(四)——锁和信号(一)
- Swoole源码学习记录(五)——锁和信号(二)
- Swoole源码学习记录(六)——Pipe管道
- Swoole源码学习记录(七)——MsgQueue
- Swoole源码学习记录(十一)——Worker,Connection
- Swoole源码学习记录(十二)——ReactorThread模块
- Swoole源码学习记录(二)——三种MemoryPool(上)
- Swoole源码学习记录(三)——三种MemoryPool(下)
- Swoole源码学习记录(八)——Reactor模块-epoll
- Swoole源码学习记录(九)——Factory模块(上)
- Swoole源码学习记录(十)——Factory模块(下)
- Swoole源码学习记录(十三)——Server模块详解(上)
- Swoole源码学习记录(十四)——Server模块详解(下)
- Swoole源码学习记录(十五)——Timer模块分析
- 学习swoole的心得
- JDBC基础知识
- SQL Access Advisor in Oracle Database 10g
- jdbc
- c二级指针原理
- git 学习笔记
- swoole源码学习——协程编号的管理和分配
- arm linux 页表创建
- 导出CSV文件中的乱码
- 剑指offer | 训练题45:孩子们的游戏(圆圈中最后剩下的数)
- STL常用函数复习之————stack
- 远程连接工具
- CSS标签选择器
- javascrip的一些基本操作
- leetcode -- 442. Find All Duplicates in an Array 【数组随机性 + 数据特点 + 整数符号位使用】