zoukankan      html  css  js  c++  java
  • C++随笔:.NET CoreCLR之corleCLR核心探索之coreconsole(1)

      一看这个标题,是不去取名有点绕呢?或者是,还有些问题?报告LZ...你的标题取得有问题,是个病句!↖(^ω^)↗!!!先不要急,其实我今天带给大家的就是CoreCLR中的coreclr。其中它是在名字叫HOST的一个子目录里面的。我的理解是HOST=宿主,GC因为是寄宿在WINDOWS中的,那么它是依靠什么寄宿呢,core-Console是我们狭义上的控制台吗?我觉得不是,我们可以把这个控制台理解为CoreCLR宿主的一个控制台,它控制了各个模块的调度,这全是我个人的理解。

      这篇文章我也是采取随机抽取代码的方式来进行讲解,因为我自己也是变学边讲,我并不比大家懂得多多少,希望大家多能砸砸我的场子。大家可以看看,首先此文件引用了windows.h,那么它肯定是和我们的操作系统打交道的一个入口了。

      我们来看看第一行代码,这其实可以表明几个知识点,第一,coreclr是基于“类”的,它不会轻易的实例化;第二点,coreclr是在runtime的时候改变其状态的;第三:Coreclr其实本身是让DLL转换成32位字符型的指针变量存储在内存中。

    // The name of the CoreCLR native runtime DLL.
    static const wchar_t *coreCLRDll = W("CoreCLR.dll");
    

     那么我们再来找一个这个W("xxx")是什么,下面我的已经做了解释

    // This macro is used to standardize the wide character string literals between UNIX and Windows.
    // Unix L"" is UTF32, and on windows it's UTF16.  Because of built-in assumptions on the size
    // of string literals, it's important to match behaviour between Unix and Windows.  Unix will be defined
    // as u"" (char16_t)
    
    //定义的作用是标准化“宽字符”在Unix内核系统和Windows内核心态之间。
    //Unix系统中,L""是UTF32,windows是UTF16.因为编译时就把它们定义成了不同的大小。
    //Unix中,u""会被定义成char16_t类型
    #ifdef PLATFORM_UNIX
    #define W(str)  u##str
    #else // PLATFORM_UNIX
    #define W(str)  L##str
    #endif // PLATFORM_UNIX
    

      StringBuffer是HostEnvironment的一个成员,来看看下面的代码,所以我认为,这里的StringBuffer,其实是和程序集有关系的,虽然我不知道有什么关系。

        // The list of paths to the assemblies that will be trusted by CoreCLR
    	//程序集路径的集合将会被CoreCLR所信任
        StringBuffer m_tpaList;
    

      下面我们还是先来看看这个StringBuilder吧。

    // Dynamically expanding string buffer to hold TPA list
    //动态扩展字符串缓冲区适应TPA动态列表
    class StringBuffer {
        static const int m_defaultSize = 4096;  //默认大小:4096个字节;4KB;1KB=1024字节
        wchar_t* m_buffer; //最小缓冲区
        size_t m_capacity; //最小区容量
        size_t m_length;  //最小字节长度
    
        StringBuffer(const StringBuffer&); //带一个StringBuffer指针变量的构造函数
        StringBuffer& operator =(const StringBuffer&); //定义一个重载操作符符,返回StringBuffer
    
    public:
    	//无参构造函数,并初始化部分成员变量
        StringBuffer() : m_capacity(0), m_buffer(nullptr), m_length(0) {
        }
    
    	//析构函数,释放缓冲区,注意析构函数是在程序结束时调用
        ~StringBuffer() {
            delete[] m_buffer;
        }
    
    	//返回已知缓冲区的指针变量的第一个节点的地址
        const wchar_t* CStr() const {
            return m_buffer;
        }
    
    	//是不是有点像.NET中StringBuilder里面的Append呢?
        void Append(const wchar_t* str, size_t strLen) {
    
    		//如果m_buffer指向“空”
            if (!m_buffer) {
    			//新建一个默认大小的数组,并分配给已知缓冲区
    			//这里之所以用数组,是因为空间可以理解为连续的空间。
                m_buffer = new wchar_t[m_defaultSize];
    			//初始化缓冲区容量
                m_capacity = m_defaultSize;
            }
    		//如果最小长度+现有长度+单位长度比最小容积要大
            if (m_length + strLen + 1 > m_capacity) {
    
    			//2倍扩容
                size_t newCapacity = m_capacity * 2;
                wchar_t* newBuffer = new wchar_t[newCapacity];
    			//这个函数我么见过,不过从字面上理解,应该是把以前的一些容量在内存中替换成新的容量
    			//PS(wcsncpy_s):Copy a wide - character string, to a maximum length
    			//wcsncpy_s拷贝宽字符串,得到一个最大长度。
                wcsncpy_s(newBuffer, newCapacity, m_buffer, m_length);
    
    			//重新赋值
                delete[] m_buffer;
                m_buffer = newBuffer;
                m_capacity = newCapacity;
            }
    		//否则不扩容拷贝
            wcsncpy_s(m_buffer + m_length, m_capacity - m_length, str, strLen);
    		//每次执行以后,最小长度都会加上已经拷贝的长度
            m_length += strLen;
        }
    };

      有句话说得好,如果单单看一个问题,我们很难有深刻的记忆,所以当我讲解StringBuffer的时候,我打算“创新”一把,我会根据代码的上下文的应用来进行讲解。在192行左右有如下代码:

    if (!m_tpaList.CStr()) return false;
    

      还有跟大家说一下为什么很多的变量都要定义成const的,因为这些东西只有在“运行时”的时候才可以改变。

    	//返回已知缓冲区的指针变量的第一个节点的地址
        const wchar_t* CStr() const {
            return m_buffer;
        }  

      那么Append是怎么用的呢?是不是很像某个方法?(*^__^*) 嘻嘻……

       m_tpaList.Append(assemblyPath, assemblyPathLength);
       m_tpaList.Append(W(";"), 1);
    

      上面提到了TPA,我个人觉得应该是一些类似程序集生成的Dll文件的一个list集合,反正我也没查到,从网上,索性先这么理解吧。下面我们再来看一个东西:HostEnvironment,下面是部分成员变量:

        // The path to this module
    	//模块的路径
        wchar_t m_hostPath[MAX_LONGPATH];
    
        // The path to the directory containing this module
    	//模块对应的物理目录的地址
        wchar_t m_hostDirectoryPath[MAX_LONGPATH];
    
        // The name of this module, without the path
    	//模块对应的名字
        wchar_t *m_hostExeName;
    
        // The list of paths to the assemblies that will be trusted by CoreCLR
    	//程序集路径的集合将会被CoreCLR所信任
        StringBuffer m_tpaList;
    

      这里面有一个很特别的成员,它是一个接口,是不是很神奇呢?C++也有接口。

       ICLRRuntimeHost2* m_CLRRuntimeHost;
    

      下面是定义:

    typedef interface ICLRRuntimeHost2 ICLRRuntimeHost2;
    

      大家也许对这个接口有一点小的疑问,为什么会有个2?有2,是不是有1呢?看下图,果然验证了我们的猜测。

      下面我们来看看余下的2个成员变量:

        //HMODULE 是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址 --来自度娘
        HMODULE m_coreCLRModule;
    
        //CoreCLR自带的日志系统
        Logger *m_log;
    

      今天时间不早了,我也准备睡觉了,以后有空会继续和大家分享的哦。

  • 相关阅读:
    hadoop中的序列化
    web服务端的架构演变
    网易考拉规则引擎平台架构设计与实践
    spring分布式事务学习笔记(2)
    质量评估面面观--聊一聊软件上线前的质量评估
    用script标签加载
    Windows下命令行下启动ORACLE服务
    笔记本优化八项
    C#编程总结(一)序列化
    学习之路十四:客户端调用WCF服务的几种方法小议
  • 原文地址:https://www.cnblogs.com/kmsfan/p/5507149.html
Copyright © 2011-2022 走看看