點選上方 藍字 江湖評談 設為關註
1.前言
之前聊過Windows下面Console.WriteLine的執行過程 本篇看下它在Linu-x64下面最新.NET9執行過程
2.受控代碼:
.NET裏面流讀寫數據一般都是透過 StreamReader 和 StreamWriter這兩個類 操作。 它們名稱空間在: System.IO。 托管庫: System.Runtime.dll,比如以下簡單的操作小例子:
using (StreamWriter writer = File.CreateText("newfile.txt"))
{
await writer.WriteLineAsync("First line of example");
await writer.WriteLineAsync("and second line");
}
StreamWriter和StreamReader分別衍生自TextWriter和TextReader。Console.WriteLine打印出的字串,則是在CLR柯瑞面直接透過TextWriter寫入到的數據流/裝置。
比如例子:
staticvoidMain(string[] args)
{
Console.WriteLine("Call Main");
}
Console.WriteLine會呼叫Out.EnsureInitialized函式, Out即是TextWriter型別,程式碼如下:
源碼地址:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Console/src/System/Console.cs
publicstatic TextWriter Out
{
get
{
static TextWriter EnsureInitialized()
{
lock (s_syncObject)
{
if (s_out == null)
{
Volatile.Write(ref s_out, CreateOutputWriter(ConsolePal.OpenStandardOutput()));
}
return s_out;
}
}
}
}
Ensu reInitialized函式裏面呼叫了Volatile.Write函式, Volatile.W rite函式 的意思是,把參數二的值寫入到參數一欄位裏面去。這裏的解釋就是 把CreateOutputWr iter(ConsolePa l.OpenStandardOutput())返回的值寫入s_out欄位,s_out也是TextWriter型別。
這裏看下CreateOutputWriter(ConsolePal.OpenStandardOutput())返回的值是啥。 CreateOutputWriter函式如下:
源碼地址:https://github.com/dotnet/runtime/blob/main/src/libraries/System.Console/src/System/Console.cs
privatestatic TextWriter CreateOutputWriter(Stream outputStream)
{
return outputStream == Stream.Null ?
TextWriter.Null :
TextWriter.Synchronized(new StreamWriter(
stream: outputStream,
encoding: OutputEncoding.RemovePreamble(),
bufferSize: WriteBufferSize,
leaveOpen: true)
{
AutoFlush = true
});
}
可以看到CreateOutputWriter返回的依舊是TextWriter,也就是說Volatile.Write把流數據寫入到流數據,然後從裝置上打印出來。
這裏寫入的流數據值到底是什麽呢?繼續看ConsolePal.OpenStandardOutput()函式,它返回的是Stream型別。
源碼地址:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Console/src/System/ConsolePal.Unix.cs
publicstatic Stream OpenStandardOutput()
{
returnnew UnixConsoleStream(Interop.CheckIo(Interop.Sys.Dup(Interop.Sys.FileDescriptors.STDOUT_FILENO)), FileAccess.Write);
}
這裏是Linux/Unix下面的操作,OpenStandardOutput裏面例項化了一個UnixConsoleStream類,UnixConsoleStream的建構函式裏面,第一個參數是Interop.CheckIo(Interop.Sys.Dup(Interop.Sys.FileDescriptors.STDOUT_FILENO))。Interop.Sys.Dup是Linux下面進行檔表項操作的函式 。CheckIo則是個檢查函式,此處可以忽略。
舉個例子,一般的來說Linux下面在終端打印一個hello World通常透過printf("hello Word")
printf -> stdout(標準輸出) -> Dup(STDOUT_FILENO) ->終端輸出
可見Linux下面是透過Dup函式傳遞參數STDOUT_FILENO進行終端操作的,UnixConsoleStream第二個參數是FileAccess.Write,表示寫入字串。然後把這個Stream封 裝後返回,透過Volatile.Write寫入到終端流裏面打印出來。
那麽其實很清晰了,流程大致如下:
Console.WriteLine->Out.EnsureInitialized-> ConsolePal.OpenStandardOutput() -> Interop.Sys.Dup->Volatile.Write
這裏面有很多可以討論和深入的細節點,了解更多可以加入我的 ,一起學習,一起進步。
往期精彩回顧