1.前言
之前聊过Windows下面Console.WriteLine的运行过程常用Console.WriteLine原理,你知道吗?本篇看下它在Linu-x64下面最新.NET9运行过程
2.托管代码
.NET里面流读写数据一般都是通过StreamReader和StreamWriter这两个类操作。它们命名空间在:System.IO。托管库:System.Runtime.dll,比如以下简单的操作小例子:
StreamWriter和StreamReader分别派生自TextWriter和TextReader。Console.WriteLine打印出的字符串,则是在CLR库里面直接通过TextWriter写入到的数据流/设备。
比如例子:
Console.WriteLine会调用Out.EnsureInitialized函数,Out即是TextWriter类型,代码如下:
EnsureInitialized函数里面调用了Volatile.Write函数,Volatile.Write函数的意思是,把参数二的值写入到参数一字段里面去。这里的解释就是把CreateOutputWriter(ConsolePal.OpenStandardOutput())返回的值写入s_out字段,s_out也是TextWriter类型。
这里看下CreateOutputWriter(ConsolePal.OpenStandardOutput())返回的值是啥。CreateOutputWriter函数如下:
可以看到CreateOutputWriter返回的依旧是TextWriter,也就是说Volatile.Write把流数据写入到流数据,然后从设备上打印出来。
这里写入的流数据值到底是什么呢?继续看ConsolePal.OpenStandardOutput()函数,它返回的是Stream类型。
这里是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")
可见Linux下面是通过Dup函数传递参数STDOUT_FILENO进行终端操作的,UnixConsoleStream第二个参数是FileAccess.Write,表示写入字符串。然后把这个Stream封装后返回,通过Volatile.Write写入到终端流里面打印出来。
那么其实很清晰了,流程大致如下: