來源:忙碌命
作者前言:我本來計劃在2012年1月MSDN雜誌發表我的第一篇關於 Windows8 文章。然而,微軟已經禁止在 MSDN 雜誌上發表任何關於 Windows 8 的文章。我不允許在我的 MSDN 雜誌專欄上發表任何關於 Windows 8 的文章,直至另行通知。對於我來說,這沒有什麼。其他出版商似乎沒有任何此類限制。為什麼冷落 MSDN 呢?好訊息是,你現在能讀到我的第一篇關於 Windows 8 的文章!具有諷刺意味的是,因為它意味著為後續關於 Windows 8 文章定下了基調。
(譯者注:讀完此文後讓人拍案而起,我在翻譯過程中加入了一些個人譯註,為了更好的把這篇文章分享給對 Windows 開發情有獨鍾的程式設計師朋友們。)
Windows 8 是微軟送給原生C++ (native C++)開發者的禮物。經過多年的推動,.NET 框架已經被視為“一個正確的道路(one true path)”,微軟正以開創性的姿態迴歸大衛.卡特勒(David Cutler)釋出的1993年的Windows NT。大衛.卡特勒(David Cutler)將 Windows 從一個名不見經傳的,被Unix開發者嘲笑的作業系統變成了一個桌面作業系統的主導者,伺服器市場作業系統的強大競爭對手。G.帕斯卡爾.扎卡里(G. Pascal Zachary)寫的觀止(Showstopper)這本書,講述了比爾.蓋茨(Bill Gates)聘請大衛.卡特勒(David Cutler)設計和開發 Windows NT 的引人入勝的故事,和他們在開發部分基礎軟體中所遇到的挑戰和鬥爭,這本書已經不再出版。
從COM 到 Common Language Runtime(CLR)
自從 Sun 證明託管程式碼(managed code )的確是一個可行的選擇,微軟在開發託管程式碼的領域裡走了一些彎路後(譯註,可能是Sun與MS的Java標準之爭),微軟在 2000年釋出了.net Framework 的beta版。在接下來的十年,.net Framework 更是深遠影響微軟的開發部門甚至整個公司。該資訊是明確的:託管程式碼在許多方面優於原生程式碼。它是更安全,更可靠,甚至可以更快!這是理論。在實踐中,結果被證明是有所不同。
微軟把 Windows Form 吹捧為一個開發 Windows 應用程式為更簡單的方法。然後微軟又開發出Windows Presentation Foundation(WPF)來解決在Windows Form的一些限制。跟著又開發 Silverlight 作為更輕、 更快的 WPF。同樣地,微軟又開發了 ASP.NET 來簡化 web 服務開發,跟著推出被認為是更好的通訊方式的 Windows Communication Foundation (WCF)(譯註,開發者都被累死了)。然而,這些技術從來沒有完全辜負炒作(never quite lived up to the hype)(注:這是反語)。在這之前我已在本專欄中寫過原生(native) Windows Web Services (WWS) API分析比較文章,其中流量(throughput)和運算元(working set)的比較就完全讓WCF激動萬分。和原生(native)的 Direct2D API [http://msdn.microsoft.com/zh-cn/magazine/dd861344.aspx]表現出令人印象深刻的效能提升。
自從開發者在2000年接觸 .NET Framework beta後,有很多關於微軟的技術發展方向的疑問。直至微軟提出把COM作為Windows軟體元件的首選技術。微軟已出版的Kraig Brockschmidt的巨大影響力的<Inside OLE 2 >這一本書,Don Box把在 Essential COM<COM本質論>這一本書中把 .NET Framework 稱為更好更簡潔的 COM。
微軟技術研究員布賴恩.哈利(Brian Harry),當時為公共語言執行時( Common Language Runtime,CLR)的開發經理,發出了現在著名的電子郵件,.NET開發郵件列表。這是親切的稱為“布萊恩的小郵件(Brian’s little email)”,長度超過五千字。這封郵件有助於澄清一些理由背後的一個棘手的問題,.NET framework 對於COM的最根本的轉變,就是遠離資源管理. COM,其核心是通過一個C + +虛擬函式表現的基於侵入性引用計數模型(invasive reference-counting)。這就是IUnknown介面,COM的引用計數模型的兩個問題被認為是不可克服的。首先是引用計數本身的成本。每次呼叫AddRef和Release通常在一個環環相扣的指令分配一個相對昂貴的參考簡單的行為(Each call to AddRef and Release typically resulted in an interlocked instruction making the simple act of assigning a reference relatively costly)(譯註:即每次要判斷介面引用是否到正確的COM物件)。公平地說,是專為使用COM元件的邊界,目的是為了設計一個通用的物件模型,這個元件可以被應用程式中的所有物件使用。應該指出的是,CLR的大部分的初始設計是為了與 Visual Basic相容,C#中還不存在。第二個問題是引用計數週期的問題。通過垃圾收集器跟蹤,週期不是一個問題。同樣,也有其他方式來解決這個問題,例如使用使用標準模板庫(Standard Template Library)的弱指標(weak pointers)。
從.NET 到 Windows Runtime
不是在建基於CLR,Windows 團隊決定是該回到原生程式碼的這一證實可靠性和效能設計要點上,COM的本質也是設計一下代偉大的Windows API的指導原則。Windows Runtime (WinRT)就是是植根於IUnknown介面的,並以把COM作一個新的方向。
拋棄中間語言程式碼編譯需要的”just-in-time”(.net的託管程式碼轉為處理器的指令的過程)。為什麼還要強迫使用者再編譯一次程式碼,你可以積極優化,提前將你的程式編譯,確保使用者第一時間獲得最快的體驗和獲得每一個支援的處理器上的所有時間?拋棄垃圾收集的執行時(garbage-collected runtimes)的不確定性資源管理。處理或不處理,這就是問題。拋棄於複雜和昂貴的託管安全模型。 Windows NT引入了一個完美的應用程式隔離和安全性模型,經得起時間的考驗。
當然,在過去十幾年也有許多教訓,也會應用於COM和現在的WinRT。在他們之前的天真的.net開發人員和 Java 和 UNIX 開發人員還想模擬 Windows 登錄檔,並提供良好的舊文字檔案作為更好的選擇。WinRT繼續使用登錄檔,因為它是一種快速、可靠的,甚至簡單的方法來管理設定。但是使一個更簡單、 更易於管理的環境的確需要一些與CLR 與相關的應用程式封裝方法。WinRT也借CLR後設資料格式的先驗(priori knowledge)元件功能的來增強COM的動態轉換(cast),舊有的QueryInterface!
.NET 開發人員哪兒去了?與 .NET Framework 初次釋出時 C + + 開發人員時收到的冷淡對待不同。微軟保證.net開發人將會繼續獲得原生程式碼一流的體驗,雖然效能由於託管程式碼的性質稍微打點折扣。由於WinRT是基於COM介面,CLR 可以容易地使用其令人印象深刻的 COM 互操作( COM interop)擴充套件WinCRT。Visual Studio IDE可以繼續為.net 開發人員提供繼續提供更好的開發體驗。與它在最近幾年所做的那樣,但是C ++開發人員仍然有真正的問題,就且是一個一流的編譯器和一個毫不妥協的Windows API(譯註:微軟需要開發標準的C++編譯器同時要支援WinRT特點,即自動為COM物件插入引用計數呼叫的程式碼,原來的Windows開發人員會排斥新的Windows API)。
從C++/CLI 到 C++/CX
那麼,是否意味著C++開發者再次使用 ATL 和 CComPtr 嗎?啊,說不準。雖然您可以使用 ATL,但是你有更好的選擇。2003 年,Visual C+ + 團隊遇到身份危機(譯註:他們認為C++也會是CLR上的成員,一分子,不再是獨立的了。)。“託管程式碼”似乎接管世界。也許他們認為需要加快步伐做出點成績出來。因此,該團隊決心重新設計一套語言擴充套件,即後來的C++/CLI。Visual C+ + 團隊著名成員 Herb Sutter 和 Brandon Bray 孜孜不倦地設計出來了一套漂亮的,一流的,最強大的 .net 程式語言。我記得我是最早寫了關於 C + + / CLI 的文章。由於我沒有編譯器,我只是簡單寫了這些文章,內容的主要資訊來源是來自我與Bray 和 Sutter的討論。
新的語言讓人激動萬分,但卻很短暫。很快 C++/CLI 的遭遇讓 Visual C + +團隊從他們的身份危機中恢復過來,他們意識到原生(native)程式碼是非常需要(great need )的,並不是所有人都要用.NET Framework.他們意識到,他們應該為注重原生程式碼,庫和工具的開發者社群提供最佳服務。我們也已經看到他們對這一決定的支援所做出的成果,今天Visual C++已經很好地支援了 C++11 的標準。
跟著,令人驚喜的是,各種關於 C++/CLI 的發展建設會議在9月捲土重來。實際上 C++/CLI 已經與 .NET沒有關係了,只是看似有關係。其中最顯著的區別在於使用”ref new”上下文關鍵字來建立物件的而不是 C + + / CLI 的 gcnew 關鍵字。
1 |
; html-script: false ]auto w = ref new Widget; |
ref new 究竟返回什麼呢?嗯,我可以更明確了:
1 |
; html-script: false ]Widget ^ w = ref new Widget; |
在 C + + / CLI ^ 運算子( ^ operator ) 宣告該變數為 CLR 引用型別的 handle。然而,這並不CLR,那麼它一定還有別的東西。此外,引用的物件 w 超出作用範圍時會發生什麼呢?嗯,事實證明,C++/CX 已引入了智慧指標( smart pointer)的語義到語言中。Widget ^ 的物件相當於帶有別出心載的語法糖的 ComPtr<Widget> 的物件(譯註:即 Syntactic sugar 原文是 with some fancy sugar coating,指計算機語言中新增的某種語法,這種語法對語言的功能並沒有影響,但是更方便程式設計師使用 ),ref new 關鍵字返回的是一個 COM 物件指標,或更確切地說,是一個WinRT物件,這個 handle 負責一個引用計數。一旦該 handle 超出範圍,便釋放引用。這也許是在程式碼中更容易理解:
1 2 3 4 5 6 |
void scope() { auto a = ref new Widget; // RoActivateInstance auto b = a; // IUnknown::AddRef a = nullptr; // IUnknown::Release for a } // IUnknown::Release for b |
RoActivateInstance 在WinRT中相當於傳統的COM的CoCreateInstance的功能。你呼叫RoActivateInstance時就直接會返回一個物件的引用計數已經增加的指標。當 a 被分配到 b 時編譯器可以確保 AddRef 被正確呼叫。同樣,每次當一個空指標值被分配到 a 和 b 超出範圍時編譯器確保 Release 會被呼叫。
這裡關鍵的是,這不是有趣的新的管理環境。這是良好的原生(native)程式碼。再者,一些程式碼幫助說明這個事實:
1 2 3 4 5 6 |
auto a = ref new Widget; auto raw = reinterpret_cast<IUnknown *>(a); auto x = raw->AddRef(); assert(2 == x); auto y = raw->Release(); assert(1 == y); |
沒有什麼說的, reinterpret_cast 使用的原生(native)程式碼 !由於底層的IUnknown介面指標,你自然可以呼叫其所有成員,包括QueryInterface(譯註:COM的操作都是必須通過IUnknown 介面查詢)。使用 AddRef 和 Release 只是向你證明這是原生(native)程式碼,因為這些程式碼已經證明 a是使用了引用計數的 COM 物件。
特定型別和使用普通C++的智慧指標來管理由此產生的引用計數(reference-counted)的介面指標。但是,有很多好的理由這樣做。正如我上面顯示的,如果你需要一些演算法或優化一個位在你的程式碼更細粒度的控制,你發現你可以輕鬆地拋開語法糖(譯註:即 Syntactic sugar 原文是 sugar coating,指計算機語言中新增的某種語法,這種語法對語言的功能並沒有影響,但是更方便程式設計師使用 ),
在本月的專欄中,我需要花些時間在 歷史上(譯註:Windows 由 .net 轉變到 WinRT 的歷史),對於我們理解 Windows 8 至關重要。下個月請與我一起開始探索 Windows 8 的細節。
肯尼.克爾(Kenny Kerr),是一個對原生 Windows 開發富有激情的軟體工匠。你可以在 http://kennykerr.ca 瞭解他。
原文地址 http://kennykerr.ca/2011/10/18/the-road-to-windows-8/ 編譯:忙碌命 laiboy