论坛首页 编程语言技术论坛

Linux2.6.36内核源码中链表、红黑树实现风格的讨论

浏览 18022 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-01-11  
thxg 写道
rubynroll 写道
我只是举了个再简单不过的例子说明 for正常结束后iterator超出范围是基本逻辑 以此说明 for_list_each_entry正常结束后,pos指向无效地址是正常逻辑


谢谢你的黑体字,终于回到正题。闭包我们不讨论,我想探讨的就是软件工程中的一些习惯,没有对错,只是可能每个人都有不同理解。

for正常结束后超出范围是正常逻辑,但for_list_each_entry结束后,不是简单的i >= MAX,而变成了一个危险的不能用的指针。i >= MAX之后,i值仍可以用,且如我前文所说,Linux内核源码中有几处就是这么用了i值。

所以 for和for_list_each_entry宏有了区别,for_list_each_entry要求程序员不要再企图引用pos的值。而Linux内核源码中也并未添加注释说明。说它存在陷阱,我想并不为过。请不要说什么X年经验的程序员都知道,我反感这样的话。想象一下gcc中的各种警告,想象一下QA工具的态度,如果它们有能力知道你的代码中存在一个危险的变量,它们会不会给你一个WARNING?从这个角度上讲,这种甚至没有加以说明的代码风格,算不算质量可控性差?

把此场景放回到内核开发环境中,也许不是什么问题。“风格”本来就是那么回事。

并不是我钻牛角尖,如果你这样的老鸟也只知道写完代码了事,那就太可惜了。如果把问题看作工程学里的问题,那它就值得深思一下了。

前面几楼提到FreeBSD,openSolaris源码风格好,很想听听你们对“风格”的见解。BSD和SUN应该都有些学院派作风,BSD本身就是大学机构,看Java的规范就知道SUN的作风。

不过光看作风似乎也没什么用。PostgreSQL再先进,大家还是喜欢MySQL(据称管理挺混乱),SUN则直接改姓了。尽管个中原因复杂,但我们是否能思考些什么呢?软件的工程学是不是需要巅覆一下呢?


好吧,很高兴看到终于回到正常讨论上了。
你说“for和for_list_each_entry宏有了区别,for_list_each_entry要求程序员不要再企图引用pos的值”这一点我不太同意,应该从更“一般化”的角度来看。

对于一个遍历操作,结束后iterator有两种可能值:
1)迭代区间的起始值 e.g. for(i=0;...)中的0是迭代区间0~(MAX-1)的起始;
2)迭代区间的下一个值,e.g. for(i=0;i<MAX;i++),迭代区间0~(MAX-1)的“下一个值”是MAX。

在你的例子中:
list_for_each_entry(pos, head, node) { 
    //... 

if (pos != NULL) printf("%d\n", pos->value);

去判断pos!=NULL这个没有道理,因为NULL既不是迭代区间的起始值,作为迭代区间的“下一个值”也不恰当。

如果你一定要问这个例子中迭代区间的“下一个值”是什么,它应该是list_entry(head, typeof(*pos), member),因为Linux link list的head是链表的锚,它包裹了链表节点,所以它既是迭代区间的“下一个”,也是迭代区间的“前一个”。理解了Linux link list的这些特点,就不会有“陷阱”了。

你要去Linux内核代码中找“工程学”的印证,估计很难了。Linux内核的很多设计是社区不断选择的结果,缺乏“学院派”或者什么派的风格,它可能不是最好维护的,也不是性能最佳的,但是往往是两者非常好的平衡结果。

订阅Linux kernel mailing list(如果你还没有这么做的话)将有助于理解Linux社区驱动的开发模式,以及体会“社区选择”是怎么做出的,就算是我这个“老鸟”的一个小小建议吧。
0 请登录后投票
   发表时间:2012-01-11  
thxg 写道
PostgreSQL再先进,大家还是喜欢MySQL(据称管理挺混乱)


php的关联数组总是有序的,用的挺方便,python的字典是无序的,用的就是不方便。所以3.0以后改成有序的了。

可能数学中的集合是无序的,这个是理论和实践的差异,最后还是改了。

据称如果表大的话PostgreSQL会速度快些,没试过。


0 请登录后投票
   发表时间:2012-01-11  
更高级的语言可以用用设计模式啥的,c可能困难些,维护老代码的话只能按原来风格咯,特别是代码量庞大无比的情况下。
0 请登录后投票
   发表时间:2012-01-12  
postgres 和 mysql的应用场景不尽相同,谈不上谁更受欢迎

现在Postgres 该有的功能也有,丝毫不差。不能再用过去的眼光去看待它
0 请登录后投票
   发表时间:2012-01-12  
mathgl 写道
postgres 和 mysql的应用场景不尽相同,谈不上谁更受欢迎

现在Postgres 该有的功能也有,丝毫不差。不能再用过去的眼光去看待它



我觉得反而是过去的眼光看的话postgres功能更多,现在功能上是mysql追了上来。至于前面朋友说的postgres的大表性能,确实表现平稳些,但mysql这些年真的进步很快,像表分区功能已经看起来像oracle一样了。

上面楼层说C这样的语言难以实践软件工程学,我觉得倒不如说现在的软件工程学太狭隘了。这是我近来的体会。
0 请登录后投票
   发表时间:2012-01-17  
向2位大侠学习了。一个for循环引发的讨论,很好啊。

一般循环里,i作为整数而已,从0到max-1,如果完成了循环,那么i应该是max。如果中途退出,应该就是0~max之间的值。
但这里的pos其实是个指针,所以不是0到max-1这样子了。出了循环的pos的值其实未必要设成null。我直观的理解,pos的值可能是base+i*node_size。

总之,其实还是个convention的问题,没所谓对错。
0 请登录后投票
   发表时间:2012-01-17   最后修改:2012-01-17
跟楼主一样疑惑,对于结构体里面放list同样不习惯,要根据list在结构体中的偏移才能取得结构对象的指针,感觉好野蛮啊。
如果要使用list_for_each宏的话还必须得将list放在结构体的第一项

对于 list_for_each_entry宏:
java和c#等一些语言的foreach循环里面pos的作用域只在循环内部。

如果能把pos的定义放在宏里面,让它作用域在for块内,可能就没有疑惑了吧。
但是这样没法知道pos的类型和大小了,除非宏再加一个参数说明什么类型。
0 请登录后投票
   发表时间:2012-01-18  
找亮点。。。
  • 大小: 164.6 KB
0 请登录后投票
   发表时间:2012-01-18   最后修改:2012-01-18
thxg 写道

从而可见,Linux内核编码的风格是假定写代码的都是高手、熟手,对各个相关部分代码都很了解。这也许是OS开发与常规项目的不同之处,这里无法用软件工程的思想去看,否则Linux源码就是个地狱般的工程。

Linux的设计哲学确实如此。局部性能为主的时候用各种方式最大化。因此关键部分总可以看见内嵌汇编,甚至于大量使用gcc提供的非标准C来最大化性能,所以就别提for的i在里面还是外面。因此不兼容gcc扩展的编译器是编不了内核的。链表作为最基本的内核组织结构,大量链表需要遍历,当然性能比"好看"重要。
0 请登录后投票
   发表时间:2012-01-19  
情已逝 写道
如果要使用list_for_each宏的话还必须得将list放在结构体的第一项

这个倒不必的,顺序无所谓啊
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics