2010-02-04 00:29:32
来自: Milo
0 bug的评论



2
== 第9章: 時間片管理 ==
整本書到這裡,終於開始說有關接近應用層的事情。但書中竟然用任天堂遊戲機 (Nintendo Entertainment System, NES, 俗稱紅白機) 去說明「多任務」的編程方式。
本章中加入一個「綫程池」,目的是避免連續太快啟動綫程(書中說兩個綫程啟動間隔需為 250ms),但綫程執行的工作完成了,綫程就結束,而不是歸還到池裡。之後又繼續啟動新綫程直到指定上限數目。
之後描述一個「任務池」,其實是一個簡單(無 priority)的任務隊列(不知道為甚麼又叫「池」,會順序調到任務。任務可以在執行中途返回,讓「任務池」把它放到隊列的尾,等待下次執行。
=== 程序bug/問題 ===
P. 432 #else 之前少了換行
=== 文中錯誤 ===
P. 416 「......(單任務)操作系統沒有任何優先級保護......」
保護模式和單任務是無關的。
P. 418 「......准備開始第二行掃描時,硬件會發出一個 IRQ 中斷。」
跟據我找到的幾個文檔,IRQ是程序執行BRK指令時才發出的。
http://nesdev.parodi us.com/NESDoc.pdf
P. 419 「任天堂遊戲機的 6502 CPU 時鐘頻率是 1Mhz,也就是說,每秒會發生100萬個時鐘周期」
應為 1.79 Mhz 或 1.66 Mhz 見 http://en.wikipedia. org/wiki/Nintendo_En tertainment_System#C entral_processing_un it
P. 419 「對於任天堂遊戲機,如果按照傳統的程序開發方式、同一時間段只有一個計算在進行,很難實現多任務開發,也就無法完成遊戲中多個角色同時動作的需求。」
遊戲看上去是多個角色同時動作,不等於要用多任務系統啊!該節描述使用每幀240次的 IRQ中斷去執行最多每秒240段代碼,文中的IRQ示範代碼如下:
void BreakFunc(void)
{
static int nSpriteIndex = 0;
switch(nSpriteIndex)
{
case 0: Sprite_Func_0(); nSpriteIndex++; break;
case 1: Sprite_Func_1(); nSpriteIndex++; break;
// ...
}
}
這段代碼亦顯示,其實每個角色的代碼是輪流執行的。跟據我參考的文檔,相信這個遊戲編程模式是完全不必要的,而且這樣做會浪費大量的 CPU 資源。
我認為一個合理的遊戲回圈應該是:
function MainLoop
while true do
foreach actor
update(actor)
flipped := false;
while flipped = false do
; 等待完成 NMI
end
end
end
function NMI
; 垂直掃描結束
foreach actor
render(actor) ; 用 actor 的狀態刷新 Picture Processing Unit(PPU)
flipped := true
end
P. 421 「程予員在 DOS 下開發遊戲程序,如DOOM等,都是攔截時鐘中斷來實現時間片切換,進而實現多角色、多任務的遊戲效果。」
不說了,完全不是事實。
P. 423 「完成一段工作後禮貌地將運行權返回給操作系統,......通常這個工作由編譯器代為完成。無論是VC還是gcc,都帶有多綫程庫(如VC下的/MT編譯參數),......但內部針對多綫程做了很多優化。」
「......在每個循環周期內嵌入一個 Sleep 調用,休眠一下,編譯器看到這一點......」
所謂多綫程庫是指 thread-safe 的庫,即庫提供的函式被多個綫程調用不會出現問題。這並不是一個優化,反而會降低效能的。
Context-switching 並不是編譯器代為完成的的。
P. 423 「多任務程序員應該養成這個習慣,在自己的任務完成一個小片段後主動調用Sleep,幫助操作系統回收時間片,以便降低系統 Loading......」
Sleep 做成 context-switching,是增加了 CPU 負荷。
這不可以成為習慣。要按照需要去使用。如果真的要等待另一個綫程,應該用適當的同步方法,而不是用 Sleep。
P. 426 「一個 CPU,同一個時間點只能執行一個計算,這是我們都知道的。」
現代的 CPU 會有 Hyper-thread、SIMD 等技術。
P. 428 「當我們啟動一個進程時,操作系統會尋找這個進程相關的程序代碼中 main 這個函數指針,......」
這不是操作系統做的,是CRT。而且 main() 運行之前還有很多EXE/ELF內的代碼要執行,包括向操作系統申請heap空間、取得 argc/argv、全域物件建構等等。
=== 其他意見 ===
P. 424 「雖然有多核 CPU 以及多 CPU 體系的計算機,但是,多任務操作系統本身和 CPU 數目並無直接關係。」
不明白書指的「無直接關係」。操作系統要把線程分配給 CPU Core,不知道這是否「關係」。
P. 429 「所有的資源都是有限的,只有時間片是無限的。」
如果是無限的資源就不用分配了,相反,因為它是很有限的才要小心使用。
P. 439 「但是,我們可能會發現,通常上述程序中間的執行體,只要計算稍微複雜一點就是一個循環體。這完全是經驗之談,沒有甚麼理論依據......。」
完全不明白為何可以這樣「抽像」一個「任務」。
P. 457 「......各個關鍵值是不斷變化的,因此,應該大規模采用"快照"思維,即每當需要使用一個全局的、多任務共享的變量時,都要有意識地使用一個本地局部變量將其拍一個快照來使用,而不能直接訪問,否則容易引發邏輯歧義等潜在的bug,導致不必要的麻煩。」
這麼做也會造成其他的 bug。如果要抽取一些多綫程的 design pattern,必須要謹慎去確定每個條件,不能「習慣性地使用了"快照"手法。」很多時候是需要顯式同步。
P. 507 「長期以來,筆者發現幾乎找不到一本專門論述多任務並行開發的書籍來幫助程序員深刻理解並行編程與單任務編程的異同。」
選擇有太多了吧,我手上都有幾本,例如最厚那本《The Art of Multiprocessor Programming》。各個平台的并發編程書籍坊間也有許多。
那個「任務池」其實無須假設任務的執行方式(初始化、循環體、結束代碼),為它預設一個狀態機。如果使用 C++,可以按需要制定不同的執行方式的抽像類,但都繼承至一個很簡單的介面(例如叫 IRunnable) )就可以了。
== 第10章: Log 日志管理系統 ==
這章很短,描述一個阻塞型的日志系統,跟據每小時輸出不同檔名的純文字文件。我所指的「阻塞」是,當綫程要輸出日志,就簡單地把函式鎖住,其他綫程在等。而且每次輸出都要重新開啟文件。
個人意見,這個日志系統對多綫程系統來說很低效。做一個非阻塞的日志系統,利用lock-free (或較簡單,不用 lock-free,至少不用等I/O的) 隊列儲存輸出,並在背景寫日志應該不難吧? 不然,偶到需要頻密輸出日志的綫程,並行都變成序列了。
== 第11章: 聚合類 ==
本來這一章描述一個類管理所有系統共用的對象(如日志、內存池等等)就結束本章,沒甚麼問題。
問題在於之後的「11.3 額外的話題: Linux 服務程序怎麼寫」,有大量的錯誤。文中竟然沒有提及 daemon 這個詞,而是自己做一套管理「服務」的工具。
== 第12章: 細節決定成敗 ==
這一章給我的感覺是一種帶有反諷的批判,個人覺得挻配合本書的。
「筆者看過很多剛出校門的同學的代碼,感覺很怪,代碼都對。但只要一代入到工程中,總是會出現這樣那樣的問題,給人的感覺總像"玩具"而不像"工具"。」
「很多年前筆者很年輕的時候,和一些老工程師溝通......這些老同事給筆者的感覺,總是揪住筆者的"軟肋"在打,問得筆者張口結舌。甚至很多時候問得筆者都沒有信心了,感覺自己學的東西在工程中一點都不正確。」
「隨著筆者這麼多年的工作......才發現這些老工程師問得很有道理,他們問的,恰恰是基於學校裡面的學生思維最容易忽視的細節,而這些細節却往往是工程成敗的關鍵。」
「對於一門語言、一個操作系統、一個平台、學生可能僅僅局限在"會用",而軟件工程師更多的要求自己"掌握"。」
「因為,"改 bug 是改不出精品的"。」
「各位讀者如果在閱讀過程中發現問題,還請不吝易教,多多批評。」
0 bug的评论




2
== 第9章: 時間片管理 ==
整本書到這裡,終於開始說有關接近應用層的事情。但書中竟然用任天堂遊戲機 (Nintendo Entertainment System, NES, 俗稱紅白機) 去說明「多任務」的編程方式。
本章中加入一個「綫程池」,目的是避免連續太快啟動綫程(書中說兩個綫程啟動間隔需為 250ms),但綫程執行的工作完成了,綫程就結束,而不是歸還到池裡。之後又繼續啟動新綫程直到指定上限數目。
之後描述一個「任務池」,其實是一個簡單(無 priority)的任務隊列(不知道為甚麼又叫「池」,會順序調到任務。任務可以在執行中途返回,讓「任務池」把它放到隊列的尾,等待下次執行。
=== 程序bug/問題 ===
P. 432 #else 之前少了換行
=== 文中錯誤 ===
P. 416 「......(單任務)操作系統沒有任何優先級保護......」
保護模式和單任務是無關的。
P. 418 「......准備開始第二行掃描時,硬件會發出一個 IRQ 中斷。」
跟據我找到的幾個文檔,IRQ是程序執行BRK指令時才發出的。
http://nesdev.parodi
P. 419 「任天堂遊戲機的 6502 CPU 時鐘頻率是 1Mhz,也就是說,每秒會發生100萬個時鐘周期」
應為 1.79 Mhz 或 1.66 Mhz 見 http://en.wikipedia.
P. 419 「對於任天堂遊戲機,如果按照傳統的程序開發方式、同一時間段只有一個計算在進行,很難實現多任務開發,也就無法完成遊戲中多個角色同時動作的需求。」
遊戲看上去是多個角色同時動作,不等於要用多任務系統啊!該節描述使用每幀240次的 IRQ中斷去執行最多每秒240段代碼,文中的IRQ示範代碼如下:
void BreakFunc(void)
{
static int nSpriteIndex = 0;
switch(nSpriteIndex)
{
case 0: Sprite_Func_0(); nSpriteIndex++; break;
case 1: Sprite_Func_1(); nSpriteIndex++; break;
// ...
}
}
這段代碼亦顯示,其實每個角色的代碼是輪流執行的。跟據我參考的文檔,相信這個遊戲編程模式是完全不必要的,而且這樣做會浪費大量的 CPU 資源。
我認為一個合理的遊戲回圈應該是:
function MainLoop
while true do
foreach actor
update(actor)
flipped := false;
while flipped = false do
; 等待完成 NMI
end
end
end
function NMI
; 垂直掃描結束
foreach actor
render(actor) ; 用 actor 的狀態刷新 Picture Processing Unit(PPU)
flipped := true
end
P. 421 「程予員在 DOS 下開發遊戲程序,如DOOM等,都是攔截時鐘中斷來實現時間片切換,進而實現多角色、多任務的遊戲效果。」
不說了,完全不是事實。
P. 423 「完成一段工作後禮貌地將運行權返回給操作系統,......通常這個工作由編譯器代為完成。無論是VC還是gcc,都帶有多綫程庫(如VC下的/MT編譯參數),......但內部針對多綫程做了很多優化。」
「......在每個循環周期內嵌入一個 Sleep 調用,休眠一下,編譯器看到這一點......」
所謂多綫程庫是指 thread-safe 的庫,即庫提供的函式被多個綫程調用不會出現問題。這並不是一個優化,反而會降低效能的。
Context-switching 並不是編譯器代為完成的的。
P. 423 「多任務程序員應該養成這個習慣,在自己的任務完成一個小片段後主動調用Sleep,幫助操作系統回收時間片,以便降低系統 Loading......」
Sleep 做成 context-switching,是增加了 CPU 負荷。
這不可以成為習慣。要按照需要去使用。如果真的要等待另一個綫程,應該用適當的同步方法,而不是用 Sleep。
P. 426 「一個 CPU,同一個時間點只能執行一個計算,這是我們都知道的。」
現代的 CPU 會有 Hyper-thread、SIMD 等技術。
P. 428 「當我們啟動一個進程時,操作系統會尋找這個進程相關的程序代碼中 main 這個函數指針,......」
這不是操作系統做的,是CRT。而且 main() 運行之前還有很多EXE/ELF內的代碼要執行,包括向操作系統申請heap空間、取得 argc/argv、全域物件建構等等。
=== 其他意見 ===
P. 424 「雖然有多核 CPU 以及多 CPU 體系的計算機,但是,多任務操作系統本身和 CPU 數目並無直接關係。」
不明白書指的「無直接關係」。操作系統要把線程分配給 CPU Core,不知道這是否「關係」。
P. 429 「所有的資源都是有限的,只有時間片是無限的。」
如果是無限的資源就不用分配了,相反,因為它是很有限的才要小心使用。
P. 439 「但是,我們可能會發現,通常上述程序中間的執行體,只要計算稍微複雜一點就是一個循環體。這完全是經驗之談,沒有甚麼理論依據......。」
完全不明白為何可以這樣「抽像」一個「任務」。
P. 457 「......各個關鍵值是不斷變化的,因此,應該大規模采用"快照"思維,即每當需要使用一個全局的、多任務共享的變量時,都要有意識地使用一個本地局部變量將其拍一個快照來使用,而不能直接訪問,否則容易引發邏輯歧義等潜在的bug,導致不必要的麻煩。」
這麼做也會造成其他的 bug。如果要抽取一些多綫程的 design pattern,必須要謹慎去確定每個條件,不能「習慣性地使用了"快照"手法。」很多時候是需要顯式同步。
P. 507 「長期以來,筆者發現幾乎找不到一本專門論述多任務並行開發的書籍來幫助程序員深刻理解並行編程與單任務編程的異同。」
選擇有太多了吧,我手上都有幾本,例如最厚那本《The Art of Multiprocessor Programming》。各個平台的并發編程書籍坊間也有許多。
那個「任務池」其實無須假設任務的執行方式(初始化、循環體、結束代碼),為它預設一個狀態機。如果使用 C++,可以按需要制定不同的執行方式的抽像類,但都繼承至一個很簡單的介面(例如叫 IRunnable) )就可以了。
== 第10章: Log 日志管理系統 ==
這章很短,描述一個阻塞型的日志系統,跟據每小時輸出不同檔名的純文字文件。我所指的「阻塞」是,當綫程要輸出日志,就簡單地把函式鎖住,其他綫程在等。而且每次輸出都要重新開啟文件。
個人意見,這個日志系統對多綫程系統來說很低效。做一個非阻塞的日志系統,利用lock-free (或較簡單,不用 lock-free,至少不用等I/O的) 隊列儲存輸出,並在背景寫日志應該不難吧? 不然,偶到需要頻密輸出日志的綫程,並行都變成序列了。
== 第11章: 聚合類 ==
本來這一章描述一個類管理所有系統共用的對象(如日志、內存池等等)就結束本章,沒甚麼問題。
問題在於之後的「11.3 額外的話題: Linux 服務程序怎麼寫」,有大量的錯誤。文中竟然沒有提及 daemon 這個詞,而是自己做一套管理「服務」的工具。
== 第12章: 細節決定成敗 ==
這一章給我的感覺是一種帶有反諷的批判,個人覺得挻配合本書的。
「筆者看過很多剛出校門的同學的代碼,感覺很怪,代碼都對。但只要一代入到工程中,總是會出現這樣那樣的問題,給人的感覺總像"玩具"而不像"工具"。」
「很多年前筆者很年輕的時候,和一些老工程師溝通......這些老同事給筆者的感覺,總是揪住筆者的"軟肋"在打,問得筆者張口結舌。甚至很多時候問得筆者都沒有信心了,感覺自己學的東西在工程中一點都不正確。」
「隨著筆者這麼多年的工作......才發現這些老工程師問得很有道理,他們問的,恰恰是基於學校裡面的學生思維最容易忽視的細節,而這些細節却往往是工程成敗的關鍵。」
「對於一門語言、一個操作系統、一個平台、學生可能僅僅局限在"會用",而軟件工程師更多的要求自己"掌握"。」
「因為,"改 bug 是改不出精品的"。」
「各位讀者如果在閱讀過程中發現問題,還請不吝易教,多多批評。」


2010-02-04 00:34:47 罂粟
最后一句话还真讽刺……2010-02-04 00:43:35 iLRainyday
博文视点赶紧跟楼主联系一下吧,把这本书的评论再集结成一本书,和肖老师的原书合成上、下两册,书名就叫做《0 Bug —— Impossible Mission》2010-02-04 00:46:57 I泼侯
评论者真是耐心,而且功力深厚。我都想写一本书请您来评,找出自己缺漏的地方。
我个人对于多线程编程,启蒙读物是《Unix 网络编程》第一和第二卷,感觉这两本书讲的是非常透彻的。
2010-02-04 00:49:49 iWangLian
最后一句是套话2010-02-04 00:51:54 大師
最后一句真是画龙点睛之笔。2010-02-04 00:54:49 iLRainyday
弄错了,这本不是博文视点出的,是电子工业社出版的。2010-02-04 01:02:16 Kouya
那個「任務池」其實無須假設任務的執行方式(初始化、循環體、結束代碼),為它預設一個狀態機。如果使用 C++,可以按需要制定不同的執行方式的抽像類,但都繼承至一個很簡單的介面(例如叫 IRunnable) )就可以了。这个完全不必,STL或者Boost的“函数对象”原理完全适用这个东西。
2010-02-04 01:03:14 x(i,n)->g
Milo 大,佩服佩服!!!2010-02-04 01:17:48 尼采
我也忍不住了:)P. 421 「程予員在 DOS 下開發遊戲程序,如DOOM等,都是攔截時鐘中斷來實現時間片切換,進而實現多角色、多任務的遊戲效果。」
這個太搞笑.... 若DOOM是這樣寫...我想會變成Matrix 了... (所有人都在子彈時間)
2010-02-04 08:12:16 西北
mark2010-02-04 09:01:47 锲而不舍求妹汁
顶最后一句话。看完这篇书评,极其庆幸自己没来得及去买该书,大量的基本原理和概念性的错误,说小了是误人子弟,说大了是浪费别人的时间等于谋财害命~
2010-02-04 12:42:19 Milo
補充一點: 「避免連續太快啟動綫程(書中說兩個綫程啟動間隔需為 250ms)」除了本書外,我未聽說過有這個問題,暫時也找不到網上相關的說法。推友認為這不大可能。
我同意一些堆友的意見,問題可能並不是出於啟動綫程本身,而是綫程執行的代碼本身有同步問題,也許造成死鎖。
如果不需要控制綫程啟動的頻率、又不需要返還綫程到綫程池,這前半章實現的「綫程池」基本上是無意義的。
2010-02-04 12:51:35 init.d
250ms的间隔是指每秒钟只能启动四个thread么?2010-02-04 13:07:31 Milo
@init.d對。書中的線程池是這樣慢慢地開始線程備用。線程結束後,就跟據線程數目上限重新啟動。
2010-02-04 13:20:06 小熊
线程可以做一个测试,创建子线程,然后两个线程立即竞争一个资源,看看子线程是否能过抢得过。不过似乎也不是很严谨。2010-02-04 13:20:43 贾里
其实我在想,假如评论未经作者允许就被使用,能否视为侵权啊?2010-02-04 13:57:57 小熊
引用和使用还是有区别的。2010-02-04 14:30:29 bakey
@milo我也写过线程池,用的是linux下的pthread,创建完马上启动,未遇到过什么问题。当然不是说一定就是正确,但是如果要说一定要等一定的时间才能启动,我希望能看到如果不等就启动的代码贴出来,然后大家一起来分析一下,我觉得这个可能和具体的业务逻辑相关。
2010-02-04 20:40:15 肖舸
我的新书《0 bug -- C/C++商用工程之道》近期已经面市,经过出版社统计,上市一个月20天左右,销售共计2500多册(出版社数据),这在专业性技术书籍中,应该还是比较乐观的。我作为作者本人,也衷心感谢各位读者的鼓励和支持,我将一如既往地努力进行后续版本的修订和写作,为大家提供更好的精品书籍。应该说,我写这本书,还是有一定目的的。
目前的社会上,讲C和C++语言的书籍汗牛充栋,但是,我发现有个问题都没有讲,就是“并行计算”。
很多学习计算机软件编程的朋友,在学校中学习到了很多很好的知识,但是,就笔者所知(可能是笔者孤陋寡闻),确实很少有大学开设《并行计算》这门课程。
但我们知道,现实社会中,目前32位多任务操作系统,如Windows、Linux、Unix等操作系统已经完全普及,哪怕连很小的嵌入式设备,如手机上,都开始使用多任务开发环境,这就要求现代程序员必须具有并行程序设计能力,但无疑,目前大多数程序员缺乏这种能力。最直观的例子就是Intel等CPU厂商,为了自己的多核CPU好销,已经开始在各地区开设程序员进修班,以各种形式向大家培训并行程序开发技能,以便解决整个业界无法适应多核多任务开发环境的需求这个问题。
我也是在这种情况下考虑写作本书的,本书虽然定位于0bug,无错化开发,宣导商业化的务实开发思维,但这仅仅是一个方面,传统单任务程序设计的无错化方法,其实已经有很多参考资料了,笔者认为再“炒剩饭”没有多大意义。笔者从第一天开始写作本书,就致力于解决大家关心的一个核心问题:“如何书写无错化的并行程序?”,这应该说是本书的核心宗旨。
这么做的意义显而易见,由于现在是互联网的社会,网络化开发采用C/S模型,但是,大量的书籍讲了Client端的开发和设计,缺很少,甚至没有书籍来描述服务器端的设计技能。但偏偏目前业界几乎所有的应用,都已经逐渐网络化,在未来的集中式和分布式运行模型下,大量的设计需求要求程序员具有多任务服务器的设计能力,这是一个现实的情况。
现在,哪怕一个很小的嵌入式家用路由器,其实都要求具有7*24小时的连续服务能力。这很好理解,大家想想自己家里的小路由器,买回来连通后,是不是很少断电和关机?
所以我作为作者,才认为这本书有这么大的现实意义,我是商用程序员,做事情讲究务实,我写书,也希望切切实实帮助现在的大多数程序员解决自己身边,现在就遇到的问题,因此我从这个角度切入,写作本书。据某些读者朋友反映,本书是:“目前为止我知道的惟一一本关注服务器端程序设计的 C++ 书。而且又是国人的原创作品,十分难能可贵。”
不过呢,俗话说,林子大了,什么鸟都有,网络作为现实社会的一个剪影,确确实实什么人都有的。本书出来后,一直受到很多不必要的干扰,这个,我在博文《关于《0 bug-C/C++商用工程之道》一书出版前后的故事》中,已经有了详细论述,此处就不再详述。
但是,我作为作者,也考虑了,不能把提批评意见的朋友都一竿子打死,这也不是客观的科学态度。毕竟,所谓“枪手”之说,我的猜测居多,并没有什么铁证,只能参考一下。因此,我又静下心来,详细阅读了一些读者,特别是一些“大牛”级的读者的批评意见。希望能找出一些真正属于自己的错误,好修订本书。这也是本着为读者负责的态度。
但是,很奇怪,我发现不管是这些大牛,还是一些小牛,批评的意见大体有个总体思想,就是本书不符合C++开发的主流规范,显得“不标准”,“野路子”。这差不多也是目前批评本人和本书最主流的意见了。这让我这个作者莫名其妙,先不论这些读者是好心还是恶意,也不论他们批评的意见是否正确,但这些意见显然我无法接受。
原因很简单,请大家看本书的书名《0 bug -- C/C++商用工程之道》,这表明,本书源代码其实是用C和C++这两种语言开发完成的,并且,在本书中任何一处提到开发语言的时候,C一定排在C++语言前面,如“C和C++无错化开发方法”。
就我这个作者本人而言,在平时工作中,我比较喜欢同时使用C和C++两种语言混合开发,当然,以C为主。这一来是工程有时候需要,二来是我个人开发习惯,毕竟,我是先学会C语言,后来才学习的C++语言。
我想这也很好理解,从第一天开始,C和C++语言编译器就是兼容多种语言的,我们知道,几乎所有版本的C和C++语言编译器,都支持内嵌式汇编开发,这是合理的,因为工业控制中很多高速端口操作,需要汇编来完成。所以现代的C和C++编译器,也有逐渐大一统的趋势,无论是VC还是gcc,均支持混合语言编程,可以说,目前我们的主流编译器,基本上都兼容三种语言,C、C++和汇编。
因此,请各位读者就事论事,在阅读过程中,不要用纯正C++语言来考察本书的源代码,本来就不是主要用C++语言开发的。
其实,我分析了一下,在我的源代码中,C和C++的比例,差不多8:2,即80%左右使用C语言开发的。对于C++语言,我本人倾向于“有限使用”,这个呢,是我的习惯,我习惯于到具体功能点的实现,使用C模式,因为即使是C++语言,函数内部都还是OP的,即面向过程的,这符合实际需要,但在模块组织上,我比较喜欢使用C++的对象概念来封装,因为确实方便。
实际上,我曾经想过,是不是以本书定名就定为“C语言商用工程之道”,但显然也不现实,因为书中确实提到了对象。
根据我个人经验呢,这比较符合现代商用系统的开发模型,一个较为大型的系统,尤其是网络相关,很多时候,系统是多种语言的混合体,有C和C++的,还有PHP和Java的,客户端开发还经常使用JavaScript和C#等,这些,我认为都是合理的。这毕竟是一个全方位满足客户需求的综合开发时代。
另外,我这里也说说本书的源代码,很多读者知道,本书虽然内部包含大量带来,甚至包含一个并行开发工程库,但我并没有提供源代码下载服务,也不提供源码光盘,很多朋友都问我为什么,其实我是有原因的。
1、本书定位为一本工程实战书籍,我认为更多是讲思路,讲解法,即share我本人的一些经验,帮助大家在以后的工程开发中,能有一些解决思路,能解决具体问题。因此,我没有认为本书的源代码有多重要。
2、本书的源代码,我本人认为它是一种语言,由C和C++语言代码,以及相关注释,以及相关文字描述共同组成的一门语言,是程序员写给程序员看的一门语言,是用来讲清楚问题的,不是拿来就用的。就好比我们上学时的伪代码,是描述逻辑使用的,仅仅是我这个作者图省事,把自己的代码直接拿出来,做了注释就写到书里了。
3、我本意是写书,不是做开源,如果做开源,我直接在网上开个库供大家下载好了,不需要写书这么麻烦的。
4、本书中代码,最少的都有两年无故障连续运营历史,最多的有9年。但我仍然不认为这些代码就一点bug都没有。只能说,在过去的工程环境下,没有暴露出bug而已。这在书中已经说明了的。
5、本书讨论的0bug,我有专文说明,一来,0bug我认为是程序员应该有的一种追求,是目标,其实我本人也没有做到的,但二来,本书讨论的0bug,可能比大多数人讨论的严厉一点点,即产品卖出钱了,你把钱揣到包包里面,并且落袋为安,不会因为维护再花出去,这个叫做0bug。我想我已经说得够清楚了,此处再次重申一下,就不劳大家不断争论了。
此处呢,我作为作者,在此做个郑重声明,也希望各位读者和准读者朋友能精确看清楚本书的定位,以及写作的目标,有的放矢地购买和阅读本书,以便更好地学有所获。
==================================================
(以下文字,纯属虚构,如有雷同,实属巧合)
From: Mxxx Yxx <xxxxxx@gmail.com>
Date: 2010-2-2 12:28
Subject: Re: 关于程序中需要用锁的原因
To: xxxx <xxxxxx@gmail.com>
x先生你好
謝謝賜教。
我對於硬體的知識很有限。我以為cache是其中一個可能做成不同步的原因。
不同的 architecture 下的同步機制會有出入,行為會有出入,所以我認為編程時應該使用平台提供的方法,而不要去假設一些行為。
RISC 的 load/hit/store 是會造成不同步,但書中說的不一致的例子是: 一個 32-bit data 寫到
memory,只寫了16-bit,另一個 thread 就去讀取。這個情況我覺得在現代的系統裡應該不存在的。
所以我才建議,如果不需要就不要寫一些底層的機制,讓讀者明白一組內存/設備要同步時使用同步機制便可以了。
如果願意, 閣下可以把這討論放到豆瓣, 我轉載也可以的。
再次感謝x先生的來信指導。
在 2010年2月2日上午11:45,xxxx <xxxxxx@gmail.com> 寫道:
> 昨天看了您在豆瓣上的书评,以及后面的争论。关于0bug的
> 有个技术问题跟您讨论一下。
> 您说的关于程序中需要用锁的原因,是由于smp系统中存在cache。我觉得,这个论断是不正确的。
> 大多数现代的smp系统,包括多核、多CPU系统,应该都是在硬件解决了这个问题。
> 比如,小规模的系统,用总线侦听协议,如:MESI协议。
> 而大规模系统,则用目录协议来解决这个问题。
> 所以一般来说,在软件实现的互斥锁中,并不会有一个显式的cache同步指令。
> 即便是在没有cache的单CPU、单核系统中,也可能存在多线程之间的数据不一致的问题。
> 例如:我们有一个简单程序,一个线程循环执行i++,另外一个线程执行i--,两个线程的循环次数相等,这两个线程的循环次数足够的大的时候,运行完毕之后,i的结果可能不等于初始值。
> 这是因为,某些RISC体系的CPU,load和store指令是分开的,当一个线程执行了load之后,如果被另外一个线程打断,此时就会出现我们不期望的结果。
> 即便在x86上,也可能出现,因为对多数语言并不会去定义,i++这条语句应该对应一条什么样的汇编指令。
> 尽管大多数x86上的编译器会把i++编译成一条inc mem[imm]指令,但这个是不保证的。程序正确性不应依赖于某个特定编译器。
>
下面是MSN的讨论记录:
xx 说:
打扰
xx 说:
昨天看了您在豆瓣上的书评,以及后面的争论。
xx 说:
关于0bug的
xx 说:
有个技术问题跟您讨论一下。
xx 说:
您说的关于程序中需要用锁的原因,是由于smp系统中存在cache。我觉得,这个论断是不正确的。
xx 说:
大多数现代的smp系统,包括多核、多CPU系统,应该都是在硬件解决了这个问题。
xx 说:
比如,小规模的系统,用总线侦听协议,如:MESI协议。
xx 说:
而大规模系统,则用目录协议来解决这个问题。
xx 说:
所以一般来说,在软件实现的互斥锁中,并不会有一个显式的cache同步指令。
xx 说:
即便是在没有cache的单CPU、单核系统中,也可能存在多线程之间的数据不一致的问题。
xx 说:
例如:我们有一个简单程序,一个线程循环执行i++,另外一个线程执行i--,两个线程的循环次数相等,这两个线程的循环次数足够的大的时候,运行完毕之后,i的结果可能不等于初始值。
xx 说:
这是因为,某些RISC体系的CPU,load和store指令是分开的,当一个线程执行了load之后,如果被另外一个线程打断,此时就会出现我们不期望的结果。
xx 说:
即便在x86上,也可能出现,因为对多数语言并不会去定义,i++这条语句应该对应一条什么样的汇编指令。
xx 说:
尽管大多数x86上的编译器会把i++编译成一条inc mem[imm]指令,但这个是不保证的。
xx 说:
程序正确性不应依赖于某个特定编译器。
xx 说:
稍等,去开会。
xx 说:
回来再讨论。
xx 说:
hi
xx 说:
关于为什么要用锁的问题,可否这样解答。
xx 说:
在多线程环境下,多个线程之间共享内存中的对象。
xx 说:
程序运行的正确性,依赖每个线程对于内存对象的更改操作的原子性。
xx 说:
用锁的目的,就是为了保证原子性。
xx 说:
而非原子更改操作产生的原因是多方面的,如:肖先生所说的原因,多个byte分开操作,是一方面的原因。
xx 说:
您说的smp体系下cache不一致性的问题,是导致这个问题的另外一个原因。
xx 说:
究竟应该用何种类型的锁,是由编程环境所定义的内存一致性模型决定的。
xx 说:
对象原子性被破坏的问题,是表现在不同层次上的。
xx 说:
他们之间又是相互联系的,如:底层内存访问的不一致,可能导致编程语言和操作系统层面不一致。
xx 说:
例如,您说的cache一致性问题,可能被传导到上层编程语言的层面。
Mxxx 说:
要正確說明為甚麼要用同步機制, 可能是挺困難的. 我有空的看看相關書籍的說法吧.
xx 说:
至于究竟应该用那种类型的锁,是由编程环境决定的,例如:如:PowerPC体系结构采用“释放一致性”模型,是比较松散的。
Mxxx 说:
atomicity 和 consistency 好像是兩個不同的 quality
xx 说:
而其模型,则要严格些。
xx 说:
是的,这是不同的概念。
xx 说:
似乎你对中文技术词汇,不是很熟悉
Mxxx 说:
小時候主要看台灣的, 現在又看內地的, 都混亂了
xx 说:
关于那本书,我没看过
xx 说:
但是那个人,我认识
xx 说:
我觉得要全面评价一本书籍,是比较困难的事情。
Mxxx 说:
這當然了, 不然就不會有評論家了.
xx 说:
您之所以产生“失望”的感觉,是因为那本书不太适合您。
Mxxx 说:
我希望可以比較客觀地在總結裡寫本書的優缺點
xx 说:
如果让一个成年人去读儿童读物,就会比较“失望”
xx 说:
当然,也并不是说儿童读物没有价值。
Mxxx 说:
其實我看前三章時, 真的感到書裡的不嚴謹, 只是靠經驗去解決問題, 也叫讀者這麼做.
xx 说:
这是他的习惯,我并不赞同。
xx 说:
但,返回头来说,这本书可能会让另外一些人学习到一些经验。也未尝不是好事。
xx 说:
我相信,每个人读书,对其内容都是选择性的读。不会是全盘接受的。
xx 说:
如果肖先生能够再谦虚一点,也许更好。
xx 说:
打扰了。
--
Mxxx Yxx
2010-02-05 10:16:11 肖舸
话说某日,我正在归妹位看书。突然,一声怒喝,某人左手板砖,右手大刀片子,身上挂着要你命3000,奔着我就过来了,吓我一跳。
他身后,还跟着一群打了鸡血的小公鸡,一个个鸡冠子竖老高,红得发紫,亢奋得嗷嗷直叫。这叫助威团。
我说大事不好,正待摆出架势接招。
没想到某人行至中途,突然刀锋一转,直接砍到无妄位的电线杆子上去了。
可怜的电线杆,脑门上挂了个“C”。
随后,板砖,脏水,烂西红柿,臭鸡蛋... ...
电线杆惨不忍睹!
我看了一下,觉得无趣,就走了... ...
一个星期以后,我突发奇想,就回去看看。
电线杆子还在,某人还在继续劈砍,不过,显然后继乏力。
助威团呢,还剩下小鸡两三只。鸡冠子也垂下来了。毕竟,从生理学上讲,雄起得太久,会钙化的,呵呵。
我看了一下,觉得无趣,就又走了... ...
... ...
... ...
“收工!”,随着导演一声令下,摄影棚一片忙乱。
“碰”,道具关闭了电闸,灯火通明的摄影棚暗了下来。
人声渐行渐远,摄影棚安静下来。
墙边的小门被微风吹开,一缕路灯的灯光,射了进来。
凄白的灯光,射到摄影棚中心的道具“C”电线杆上。
杆下靠坐着某人,嘴里喃喃地说:
“哥拍的不是C,哥只是想成为传说... ...”
----仅以此文,纪念2010年春,某人以C++拍C,以及替伪代码debug的神勇之战
2010-02-08 15:34:28 南瓜阿二
这些年看过空洞乏味的书,看过粘贴拷贝的书,看过观点陈旧的书,但是所幸没看过如此这般瞎讲的书。给出版社的建议:开除该书的编辑,把Milo先生的评论集结成书,送到每一个不幸读了出书的读者手里,同时学习汽车厂商把原书召回
给买了该书的读者的建议:逐一向出版社和作者索赔,索赔项目包括,1,因为该书的谬论给你的项目造成的损失,2,阅读该书浪费的时间
给作者公司的建议:解聘该员工,并及时和客户沟通该员工在公司并为负责任何开发工作,以及时消除客户的担心。
2010-02-08 16:22:14 thomascatlee
P. 423 「多任務程序員應該養成這個習慣,在自己的任務完成一個小片段後主動調用Sleep,幫助操作系統回收時間片,以便降低系統 Loading......」忍不住注册来说两句,“在自己的任务完成一个小片段后主动调用sleep”,古老的伪多任务操作系统可能需要任务主动释放CPU,目前比较主流的多任务操作系统用这种做法对任务的实时性有很大影响,正确的方法是,pend任务所需的关键资源,任务调度由操作系统进行。
2010-02-11 18:16:43 肖舸
嗯,当当,china-pub是专业售书的网店,和这个网站有个差别。这两家一定要买了书才可以打分的,这个网站则是随便什么人,高兴不高兴了都可以打分。因此,当当和china-pub,不管评语怎么样,打分的一定是读者,其评分有效性,当然比这个网站要好很多。
建议各位读者可以参考一下上述两个网店评分。
我作为作者也总结了一下,批评意见主要是以C++的标准和规范来批评本书,问题是,本书的名字《0bug-C/C++商用工程之道》,这本来就是以C为主写的书。
一本书,见仁见智,目前看了我书的朋友,大多还是说好的。
关于《0 bug-C/C++商用工程之道》一书出版前后的故事
http://blog.csdn.net
揭秘 五 毛 党 真相 已成产业的" 网 络 打 手 "
http://blog.csdn.net
《0bug-C/C++商用工程之道》究竟用了什么编程语言
http://blog.csdn.net
0bug到底碰痛了谁的神经?
http://blog.csdn.net
2010-02-11 19:10:26 Milo
@----因為你在我的書評中回覆, 我認為你所說的是針對本書評。如果不是, 請告之, 我會幫你刪除.
> 嗯,当当,china-pub是专业售书的网店,和这个网站有个差别。这两家一定要买了书才可以打分的,这个网站则是随便什么人,高兴不高兴了都可以打分。
> 因此,当当和china-pub,不管评语怎么样,打分的一定是读者,其评分有效性,当然比这个网站要好很多。
> 建议各位读者可以参考一下上述两个网店评分。
我已給你連接, 說明我是在當當買的。
> 我作为作者也总结了一下,批评意见主要是以C++的标准和规范来批评本书,问题是,本书的名字《0bug-C/C++商用工程之道》,这本来就是以C为主写的书。
如果你覺得我的批評意見主要和編程語言有關, 那我只可以認為你沒認真看過我這幾篇書評。
2010-02-11 19:17:54 x(i,n)->g
希特勒统治德国的时候,纳粹分子发起了疯狂反对爱因斯坦的活动,甚至有一百名教授联名申明说,爱因斯坦的理论是错误的。有人就此事问到爱因斯坦。爱因斯坦平静的回答道:“要是我错了,只需要一名教授就够了。”
2010-02-11 20:03:34 iLRainyday
很多人并不是在chinapub上买书,所以在douban上打分的未必没有买过本书;在chinapub上买过书的,也未必能看出书里的问题,这是最可悲的,被误导了,还浑然不知的在叫好;
chinapub上刷星容易的很,尤其是国内作者写的书,比如李刚的《疯狂xxx》系列,都是靠几个书托在chinapub买过书之后把分数给刷成了四星。为什么确定是书托?自己去看看这些人的注册时间以及之前写过的评论历史,很容易就能分辨出来;
不过可以肯定的是,只要来过豆瓣,或者了解这个事件的人,基本上都不会再买这本书了。
2010-02-11 20:12:37 iLRainyday
肖老师颇像北京师范大学的季广茂教授,对于对自己提出反对意见的四川师范大学的钟华教授,直呼其“低级下流、不择手段、无耻、蛮横、是个‘屁眼教授’”。嘴里叫着欢迎指教,但是从来都不知道西方的现代学术讨论规则。一看文章就要推断别人“不可告人”的用心和动机。殊不知,同行对你真正的尊重就是帮你指出你作品中的问题。把内行的讨论当作诽谤,把chinapub以及csdn上无知学生的追捧当作赞美,呵呵,我还能说什么呢?去看看梁文道先生的《常识》一书中第166页那篇《大学教授:学术辩论不用骂娘》吧。
2010-03-26 16:19:59 葡萄
做人还是有些修养的好。。。2010-08-23 05:13:26 tingmei
Milo :真正的程序员,是我学习的榜样。我买了肖的这本书,一个字:悔!正想看看大家的意见,不留神看到了 Milo 的评论和这些回帖。真的是说了我想说的。但是, Milo 的涵养太好了,要是我,干脆二话不说,只要见到这个肖,见一次打一次!
这本书绝对是骗钱的,起了一个哗众取宠的书名……那个肖无论技术、人品、人格、态度、心胸……实在是让人鄙视!中国的程序员之耻!当记入史册!肖疴,我记住这个卑鄙的人了!
> 我来回应