分析pid源代码,改写成线程id以及提出的问题
来源:互联网 发布:云南师范大学网络课程 编辑:程序博客网 时间:2024/05/16 14:35
修改后的代码,每一行都有注释。但是在该方法中,提出一个问题。比如当循环到第32767次时,我们回收进程号32766。
所以分配的进程号为32766,再进入下一次循环此时32767进程号已经被分配,然而last_tid等于32766
此时查找最新可分配的Id号,调用find_next_zero_bit(void *addr, int size, int offset)方法,此时offset = 32767 不可分配,offset+1.
不满足条件,跳出循环并返回32768,该id超出界限,返回-1.
而不会再从头搜索,此时如果存在tid = 3 可用,也不能将其分配出去。
如下图所示:
该问题已经解决,修改下面方法,当有空闲ID时,重复循环查找
static int find_next_zero_bit(void *addr, int size, int offset)
{
unsigned long *p;
unsigned long mask;
//如果小于最大空间
while (offset < size && tidmap.nr_free)
{
//偏移地址
p = ((unsigned long*)addr) + (offset >> (sizeof(unsigned long) + 1));
mask = 1UL << (offset & (sizeof(unsigned long) * BITS_PER_BYTE - 1));
//该位是否可分配,可分配,则跳出循环
if ((~(*p) & mask))
{
break;
}
//如果不可分配,则判断下一位
++offset;
//如果超过最大数,相&之后可得余数,这样即可重新查找
offset = offset & BITS_PER_PAGE_MASK;
}
原代码如下所示:
#include<iostream>
using namespace std;
/* max tid, equal to 2^15=32768
最大线程id号,为了兼容16位机器*/
#define TID_MAX_DEFAULT 0x8000
/* page size = 2^12 = 4K
PAGE_SHIFT :偏移量
将1UL向左偏移12位,即为结果 */
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
/*
每页的位数为2^15,每一位对应一个线程号
*/
#define BITS_PER_BYTE 8
#define BITS_PER_PAGE (PAGE_SIZE * BITS_PER_BYTE)
#define BITS_PER_PAGE_MASK (BITS_PER_PAGE - 1)
/*
定义位图的数据结构
nr_free:空闲的位数
page:字符数组
*/
typedef struct tidmap
{
unsigned int nr_free;
unsigned long page[PAGE_SIZE/sizeof(unsigned long)];
} tidmap_t;
/*
初始化这个数据结构,默认每个字符的值为0,有MAX个空闲位置
*/
static tidmap_t tidmap = { TID_MAX_DEFAULT, {0} };
//初始化last_tid:用来表示最新分配出去的线程号
static int last_tid = -1;
//测试需要分配出去的位是否可用,可用则返回0,不可用返回1
static int test_and_set_bit(int offset, void *addr)
{
unsigned long mask = 1UL << (offset & (sizeof(unsigned long) * BITS_PER_BYTE - 1));
unsigned long *p = ((unsigned long*)addr) + (offset >> (sizeof(unsigned long) + 1));
unsigned long old = *p;
*p = old | mask;
return (old & mask) != 0;
}
//清空位数
static void clear_bit(int offset, void *addr)
{
//offset获得的是线程id的偏移量,addr则是首地址
//mask:将1UL向左偏移,偏移的位数是offset%32后的余数
//这里以offset = 67做例子,67%32 = 3 ,mask = 8 即00****00 1000,即第3位的值为1,其他为0
unsigned long mask = 1UL << (offset & (sizeof(unsigned long) * BITS_PER_BYTE - 1));
//将offset向右偏移,获得的结果是offset/32的结果,即地址偏移量
//地址偏移量+首地址可求出实际地址
//offset = 67 67/32 = 2,地址偏移量为2 加上首地址,获得第64~95位
unsigned long *p = ((unsigned long*)addr) + (offset >> (sizeof(unsigned long) + 1));
//获得实际地址上的值
unsigned long old = *p;
//将该字上的第3位的数置0,即第67位
*p = old & ~mask;
}
//找到下一个为0的位
//addr:首地址
//size:最大空间
//offset:测试开始位
static int find_next_zero_bit(void *addr, int size, int offset)
{
unsigned long *p;
unsigned long mask;
//如果小于最大空间
while (offset < size)
{
//偏移地址
p = ((unsigned long*)addr) + (offset >> (sizeof(unsigned long) + 1));
mask = 1UL << (offset & (sizeof(unsigned long) * BITS_PER_BYTE - 1));
//该位是否可分配,可分配,则跳出循环
if ((~(*p) & mask))
{
break;
}
//如果不可分配,则判断下一位
++offset;
}
return offset;
}
//分配线程ID
static int alloc_tidmap()
{
//获得最新分配出去的线程号+1,即可能分配出去的下一个线程号
int tid = last_tid + 1;
int offset = tid & BITS_PER_PAGE_MASK;
//如果没有空闲ID,返回-1,分配不成功
if (!tidmap.nr_free)
{
return -1;
}
//找到从last_tid开始下一个为0的位
offset = find_next_zero_bit(&tidmap.page, BITS_PER_PAGE, offset);
//如果该位没有超出界限,并且测试该位可分配
if (BITS_PER_PAGE != offset && !test_and_set_bit(offset, tidmap.page))
{
//减小可用量
--tidmap.nr_free;
//更新最新分配出去的tid号,并返回该tid
last_tid = offset;
return offset;
}
return -1;
}
//释放线程ID
static void free_tidmap(int tid)
{
//首先获得线程id,与BITS_PER_PAGE_MASK相与的目的?是为了防止出界么?这个我也不太了解
//结果与tid一样
int offset = tid & BITS_PER_PAGE_MASK;
//将空闲数+1
tidmap.nr_free++;
//清空位数
clear_bit(offset, &tidmap.page);
}
int main()
{
int i;
for (i = 0; i < TID_MAX_DEFAULT ; ++i)
{
cout<<"nr_free:"<<tidmap.nr_free<<",i="<<i<<", tid ="<< alloc_tidmap()<<endl;
}
free_tidmap(32766);
cout<<"free 32766"<<endl;
cout<<"nr_free"<<tidmap.nr_free<<"i=32766,tid="<<alloc_tidmap()<<endl;
free_tidmap(3);
cout<<"free 3"<<endl;
cout<<"nr_free"<<tidmap.nr_free<<"i=32769,tid="<<alloc_tidmap()<<endl;
return 0;
}
- 分析pid源代码,改写成线程id以及提出的问题
- BeanUtils代码改写成BeanCopier时出现的问题
- JAVA线程dump的分析 --- jstack pid
- JAVA线程dump的分析 --- jstack pid
- JAVA线程dump的分析 --- jstack pid
- JAVA线程dump的分析 --- jstack pid
- JAVA线程dump的分析 --- jstack pid
- JAVA线程dump的分析 --- jstack pid
- 将 java 改写成 beanshell 的经验之谈
- NDK C 改写成C++时编译出现问题的解决方法
- 用c++写成的最小二乘法的源代码
- 我的几个作品源代码公载(敬告:单纯的技术问题请在BLOG提出)
- Java线程池(ThreadPoolExecutor以及相关源代码分析)
- 进程PID、线程ID、实例Instance、句柄Handle的关系及App.hInstance 的用途
- C++改写成C
- PostThreadMessage()线程ID无效的问题
- SVM(一) 问题的提出
- 当年提出的一个问题
- startActivityForResult与startActivity的不同之处
- php中的@符号与#符号
- PHP中的四种字符串表达方法
- ubuntu 卸载程序
- UBOOT环境变量以及使用设置
- 分析pid源代码,改写成线程id以及提出的问题
- 如何在面试时写出高质量的代码(转)
- 博客园推荐博客
- a标签中调用javascript的几种方法
- AJAX无刷新提交表单的方法
- 中国联通奠定3G市场龙头地位
- 容器类
- 跳转视图
- 一个很好的视频跟踪算法-来自捷克博士论文