精华内容
下载资源
问答
  • Android命名空间使用总结
    千次阅读
    2017-02-03 22:04:05

           Android的命名空间在开发中使用的频率其实是比较少的,但是对于开发者来说还是要学会简单使用的,它的作用场合一般是用户自定义View的组件中!
           简单的应用举例,比如:一个自定义的进度条组件,在布局文件中设置好最大值,然后用自定义组件的代码来获取布局文件中设置的数字。
           Android命名空间实际考查的是资源文件Attribute的获取使用!

    一.Android命名空间的基础知识要点

    Android命名空间有三部分内容:

    (一)资源文件的定义

    资源文件放在res/calues目录下,(文件名任意,一般设置为attrs.xml)示例代码:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <!--定义属性  -->
        <attr name="titleName"/>
        <attr name="numberOne"/>
          <attr name="numberTwo"/>
          <!--定义styleable对象来组合多个属性  -->
          <declare-styleable name="MyViewStyle">
              <attr name="titleName"/>
              <attr name="numberOne"/>
          </declare-styleable>
    
        </resources>

    (二)自定义组件的创建MyView,以及获取资源数据的设置,主要代码:

    //获取styleable资源对象
            TypedArray typeArray=context.obtainStyledAttributes(attrs,R.styleable.MyViewStyle);
            //获取styleable资源对象里面的字符串
            String name=typeArray.getString(R.styleable.MyViewStyle_titleName);
            //获取styleable资源对象里面的数字
            int numberOne=typeArray.getInt(R.styleable.MyViewStyle_numberOne, 0);

           上面styleable中是字符串还是数字是一般由布局文件中来设置就可以(属性值后面的值有字母或符号就是字符串,),当然也可以在资源文件中定义好,比如上面资源文件中

     <!--定义属性  -->
        <attr name="titleName"  format="string"/>
        <attr name="numberOne"  format="integer"/>

           这时如果布局文件中的numberOne为字符串时也是会报错!

    (三)布局文件的设计

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
    xmlns:myxmlns="http://schemas.android.com/apk/res/com.example.attribute"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
         >
        <!--使用自定义组件,并指定属性资源文件中的属性  -->
        <com.example.attribute.MyView
             android:layout_width="match_parent"
            android:layout_height="20dp"
            android:background="#f00"
            myxmlns:titleName="这是我的测试命名空间的标题"
            myxmlns:numberOne="100"
            myxmlns:numberTwo="200"
            />
    
    </LinearLayout>

    上面有两个关键的地方要注意:
           一个是命名空间的定义,这里名称myxmlns是任意定义的,但是”=”后面的固定格式:”http://schemas.android.com/apk/res/+自定义组件的包名。
           另一个是命名空间后面的属性,必须要在资源文件中定义好,如下:

    <!--定义属性  -->
         <attr name="titleName"/>
         <attr name="numberOne"/>
         <attr name="numberTwo"/>

    之后这里才能在布局文件中设置的就是这三个属性:

            myxmlns:titleName="这是我的测试命名空间的标题"
            myxmlns:numberOne="100"
            myxmlns:numberTwo="200"

           如果没有定义好直接设置是后报错的,比如这里写:
           myxmlns:numberThree=”300”,因为numberThree没有在资源文件中定义!

    到这里Android命名空间的知识点就大概介绍完毕了。
    下面是介绍两个示例程序:

    二.命名空间的属性值的获取

    (一)資源文件的定义,文件名attrs.xml在res/values目录下

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <!--定义属性  -->
        <attr name="titleName"  format="string"/>
        <attr name="numberOne"  format="integer"/>
          <attr name="numberTwo"/>
          <!--定义styleable对象来组合多个属性  -->
          <declare-styleable name="MyViewStyle">
              <attr name="titleName"/>
              <attr name="numberOne"/>
          </declare-styleable>
    
          <!--   定义styleable2对象来组合多个属性  -->
          <declare-styleable name="MyViewStyle2">
              <attr name="titleName"/>
              <attr name="numberOne"/>
               <attr name="numberTwo"/>
          </declare-styleable> 
        </resources>

           上面可以创建多个styleable组合,组合里面可以有一个或多个定义好的属性。

    (二)自定义组件的设计

    package com.example.attribute;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    
    public class MyView extends View{
    
        public MyView(Context context, AttributeSet attrs) {
            super(context, attrs);
            //获取styleable资源对象
            TypedArray typeArray=context.obtainStyledAttributes(attrs,R.styleable.MyViewStyle);
            //获取styleable资源对象里面的字符串
            String name=typeArray.getString(R.styleable.MyViewStyle_titleName);
            //获取styleable资源对象里面的数字
            int numberOne=typeArray.getInt(R.styleable.MyViewStyle_numberOne, 0);
    
            //获取第二组styleable资源对象
            TypedArray typeArray2=context.obtainStyledAttributes(attrs,R.styleable.MyViewStyle2);
            String name2=typeArray2.getString(R.styleable.MyViewStyle2_titleName);
            int numberOne2=typeArray2.getInt(R.styleable.MyViewStyle2_numberOne, 1);
            int numberTwo2=typeArray2.getInt(R.styleable.MyViewStyle2_numberTwo, 2);
    
            //打印第一组styleable资源对象里面的数据
             Log.e("TAG","typeArray中titleName="+name+",numberOne="+numberOne);
             ///打印第二组styleable资源对象里面的数据
             Log.e("TAG","typeArray2中titleName="+name+",numberOne="+numberOne+",numberTwo="+numberTwo2);
    
        }
        public MyView(Context context) {
            super(context);
    
        }
    
    }

    (三)布局文件activity_main.xml中的调用

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:myxmlns="http://schemas.android.com/apk/res/com.example.attribute"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
         >
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="命名空间" />
        <!--使用自定义组件,并指定属性资源文件中的属性  -->
        <com.example.attribute.MyView
             android:layout_width="match_parent"
            android:layout_height="20dp"
            android:background="#f00"
            myxmlns:titleName="这是我的测试命名空间的标题"
            myxmlns:numberOne="100"
            myxmlns:numberTwo="200"
            />
    
    </LinearLayout>

           这里MainActivity中没有什么代码就不写了,但是oncreate中的setContentView(R.layout.activity_main);是不能少的!
    运行程序后,显示的界面:
    j1
    上面没啥内容,重点是资源数据的获取,下面是Log的数据:
    j2
           到这里资源文件的数据就能成功获取了!Android命名空间的使用也是简单演示使用了一遍!

    三.下面是命名空间的一个简单应用

           设计一个自定义的ImageView图片组件,在布局文件中设计几秒后完全显示它的图片!
    效果:
    s3
    设计过程:

    (一)资源文件的定义

    资源文件放在res/calues目录下,attrs.xml代码:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <!--定义属性  -->
        <attr name="duration"  format="integer"/>
          <!--定义styleable对象来组合一个或多个属性  -->
          <declare-styleable name="MyViewStyle">
              <attr name="duration"/>
          </declare-styleable>
    
        </resources>

    (二)自定义组件的设计

    package com.example.attribute2;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.os.Handler;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.widget.ImageView;
    
    public class MyImageView extends ImageView{
        //图片透明度每次改变的大小
        int alphaDelta=0;
        //记录图片当前的透明度
        int curAlpha=0;
        //每隔多少秒改变一次
        final int SPEED=300;//300毫秒改变一次透明度
        public MyImageView(Context context, AttributeSet attrs) {
            super(context, attrs);
            //获取styleable资源对象
            TypedArray typeArray=context.obtainStyledAttributes(attrs,R.styleable.MyViewStyle);
    
            //获取styleable资源对象里面的数字
            int duration=typeArray.getInt(R.styleable.MyViewStyle_duration, 1000);
            Log.e("TAG","duration="+duration);
            //计算每次改变的透明度的大小
             alphaDelta=255*SPEED/duration;
             setImageAlpha(curAlpha);//刚开始不显示
            //按发送消息,通知系统改变图片的透明度
             handler.sendEmptyMessageDelayed(111, SPEED);
    
        }
        public MyImageView(Context context) {
            super(context);
    
        }
        Handler handler=new Handler(){
            public void handleMessage(android.os.Message msg) {
                if (msg.what==111) {
                    if (curAlpha>=255) {
                        curAlpha=255;
                        MyImageView.this.setImageAlpha(curAlpha);
                        handler.removeMessages(111);
                    }else{
                        //每次增加curAlpha的值
                    curAlpha+=alphaDelta;
                    MyImageView.this.setImageAlpha(curAlpha);
                    Log.e("TAG","curAlpha="+curAlpha);
    
                    //按发送消息,通知系统改变图片的透明度
                     handler.sendEmptyMessageDelayed(111, SPEED);//这里是自己给自己发消息!
                    }
    
                }
    
            };
        };
    
    }

           上面图片每次透明度的改变可以用定时器来设计,但是定时器要用到子线程,有时程序退出线程还在执行,所以我一般尽量少用线程相关的。

    (三)布局文件activity_main.xml中的调用

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:myxmlns="http://schemas.android.com/apk/res/com.example.attribute2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
         >
    
        <TextView
    
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="这是一个慢慢显示的图片" />
        <!--使用自定义组件,并指定属性资源文件中的属性  -->
        <com.example.attribute2.MyImageView
            android:src="@drawable/yts"
             android:layout_width="match_parent"
            android:layout_height="match_parent"
            myxmlns:duration="6000"
    
            />
    
    </LinearLayout>
    

    (四)主方法的代码很简单:

    package com.example.attribute2;
    
    import android.app.Activity;
    import android.os.Bundle;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }

           上面程序中可以看到程序的调用是很方便的,只要把自定义的组件复制进去后,可以直接在布局文件中调用和设置组件的参数。这也许就是命名空间的方便的地方,也就是调用方便(方便调用者),但是设计起来还是要写多一些代码。

    三.Android命名空间的总结

    (一)资源文件中的知识

    定义资源文件示例代码:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <!--定义属性  -->
        <attr name="titleName"/>
        <attr name="numberOne"/>
          <attr name="numberTwo"/>
          <!--定义styleable对象来组合多个属性  -->
          <declare-styleable name="MyViewStyle">
              <attr name="titleName"/>
              <attr name="numberOne"/>
          </declare-styleable>      
        </resources>

    布局文件的示例代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:myxmlns="http://schemas.android.com/apk/res/com.example.attribute"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
         >
        <!--使用自定义组件,并指定属性资源文件中的属性  -->
        <com.example.attribute.MyView
             android:layout_width="match_parent"
            android:layout_height="20dp"
            android:background="#f00"
            myxmlns:titleName="这是我的测试命名空间的标题"
            myxmlns:numberOne="100"
            myxmlns:numberTwo="200"
            />
    
    </LinearLayout>

    1.attr元素作用:

           定义一个属性,可以在布局文件中使用命名空间的名称结合属性定义属性的具体值。

    2.declare-styleable子元素:

           定义一个styleable对象,每个styleable对象就是一组attr属性的集合,里面可以定义多个定义好的属性,使用java代码可以获取该组集合里面属性的值。
           命名空间资源文件代码的文件的命名也是任意的,但是为了更好标识一般写attrs.xml

    (二)命名空间xmlns的名称:

           名称是可以任意的,下面使用的命名空间名称也是上面必须的,上面的命名空间名称是myxmlns。
           xmlns表示的是命名空间的意思,这里可以看到根布局中必须要有一个android的命名空间,并且格式也是固定的,只有定义了android系统的命名空间才能使用android中某些组件的的属性,比如android:textSize=“18” 后android:backColor=“#f00”等等。

    (三)最后强调一下命名空间的作用:

           命名空间可以直接在布局文件中定义好自定义属性的一些属性,调用时只要在布局文件中设置属性,而不用再去代码中设置,但是自定义组件中必须要做代码处理(获取和设置!)。
           简单的说就是提前做处理,调用方便!
           但是正常开发的程序中很少用到
           除非是你经常要用到打自定义组件,并且要设置多个属性值,可以考虑使用命名空间,简化调用程序步骤!

    更多相关内容
  • 【C++】-命名空间的概念及使用

    千次阅读 2021-04-09 18:53:20
    本篇文章我将向大家介绍C++中一个非常重要的语法,命名空间的概念。 首先一开始我想先请大家一段C语言代码: #include <stdio.h> int scanf = 0; int main() { printf("%d\n", scanf); } 很简单的一段代码...

    本篇文章我将向大家介绍C++中一个非常重要的语法,命名空间的概念。

    首先一开始我想先请大家一段C语言代码:

    #include <stdio.h>
    
    int scanf = 0;
    
    int main()
    {
    	printf("%d\n", scanf);
    }
    

    很简单的一段代码,这里我问一个最简单的问题,我的这段代码有没有错?

    这个时候可能有人觉得,必然是错的,scanf是C语言的一个标准输出函数啊,你怎么能用函数名来当变量呢?

    我要告诉大家的是,C语言中共有32个关键字,而C语言语法中只是规定不能用关键字来命名变量,但是并没有规定不能用函数名来命名。也就是说我用scanf来做变量名从语法角度出发是没有任何问题的,不过我想说的是,这段代码确实是有问题的,下面我们就来编译一下这段代码:
    在这里插入图片描述
    可以看到,提示的错误信息是scanf被重定义了,下面我来解释原因。

    我想大家C语言阶段都曾学到过,生成一个可执行程序需要预处理,编译,汇编,链接四个过程。而预处理阶段会将头文件里包含的所有函数都展开,而scanf是<stdio.h>这个头文件里包含的一个函数,也就意味着这个函数在预处理之后会被展开到当前代码中。

    这样当你在main函数中打印scanf的时候就会出现问题了,你要打印的scanf究竟是库函数中的函数名,还是你主动创建的全局变量,这就会产生歧义,从而导致错误。

    这就是C语言语法中一些不严谨的地方。这里可能有人要说了,这有什么,那我定义变量名的时候小心一点,尽量不和库函数名发生冲突不就好了。

    这里我来为大家举一个例子,假设你现在是一名公司的员工,你们组一共是十个人,现在正在共同完成一个项目。实现一个大项目,肯定是需要协作进行的,你的组长现在把这个项目分为好几个模块,然后你们每个人负责一部分。当你和你的组员都完成之后,再把这些模块汇总成完整的项目。

    现在你有一个同事张三,你在你所负责模块的时候创建了一个变量length,而张三又在它的模块里创建了一个同样命名为length的变量。你们两个创建的变量作用肯定是不同的,但是变量名却一样,这样最后在汇总的时候项目中是不是就会出现两个名为length的变量,从而导致变量的重定义。

    我举这个例子的目的是为了告诉大家,有时候用C语言写代码的时候是难以解决命名冲突的问题的,而C++中为了解决这个问题就提出了命名空间的概念。

    下面我们就来看命名空间是一个怎样的东西。


    1. 命名空间的概念

    在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的

    2. 命名空间的定义

    定义命名空间,需要使用到namespace 关键字,这个关键字的作用就是定义一个命名空间。namespace后面跟 命名空间的名字 ,这个名字就跟变量名一样可以随便取,然后 接一对{} 即可,{}中即为命名空间的成员。

    现在我们就来对上面的错误代码进行修正:

    #include <stdio.h>
    
    namespace ret 
    {
    	int scanf = 0;
    }
    
    int main()
    {	
    	printf("%d\n", scanf);
    }
    

    上述代码中我将定义的名scanf的全局变量封装在了名为ret的命名空间中了,命名空间就相当于C++中一块被隔离起来的空间,只要你不将它打开,里面的东西就不会出来。下面我们再来运行一下这段代码:
    在这里插入图片描述
    可以看到这次并未发生命名冲突,成功的打印出了一个值到屏幕上。这是因为命名空间的存在将我们原本定义的全局变量scanf给封装了起来,只要不打开,外界就不会接收到这个变量。因此代码中只有标准输入函数scanf,最终打印的结果是将该函数的地址以十进制的形式打印到了屏幕上。

    好,到这里我们算是初步的认识了一下命名空间是如何定义的,以及它的作用。接下来的问题是,你把变量封装在命名空间中,总得取出来用吧,关起来不用,那你还定义它干嘛。

    下面来看看我们是如何使用命名空间的。

    3. 命名空间的使用

    下面我来介绍命名空间的三种使用方法。

    3.1 加命名空间名称及作用域限定符

    #include <stdio.h>
    
    namespace N
    {
    	int a = 10;
    	int b = 20;
    	int c = 30;
    }
    
    int main()
    {
    	printf("%d\n", N::a);
    	return 0;
    }
    

    代码中的 '::'为域作用限定符 ,N::a的作用是直接指定a变量就是N空间里命名的变量。

    运行结果:
    在这里插入图片描述

    3.2 使用using将命名空间中成员引入

    #include <stdio.h>
    
    namespace N
    {
    	int a = 10;
    	int b = 20;
    	int c = 30;
    }
    
    using N::b;
    
    int main()
    {
    	printf("a = %d\n", N::a);
    	printf("b = %d\n", b);
    	return 0;
    }
    

    using也是c++中的一个关键字,该关键字的作用是展开命名空间。代码中的using N::b指的是把b单独展开在全局域中,展开之后的b就相当于一个没有被封装的全局变量,可以在任何地方调用。

    运行结果:
    在这里插入图片描述

    3.3 使用using namespace命名空间名称引入

    #include <stdio.h>
    
    namespace N
    {
    	int a = 10;
    	int b = 20;
    	int c = 30;
    }
    
    using N::b;
    using namespace N;
    
    int main()
    {
    	printf("a = %d\n", N::a);
    	printf("a = %d\n", b);
    	printf("c = %d\n", c);
    	return 0;
    }
    

    using namespace N相当于将命名空间N里的变量全部展开到全局域中,这样域中所有变量的调用都会不受限制。

    运行结果:
    在这里插入图片描述
    注意:第三种方法并不推荐使用,因为全部展开根本没有起到命名空间的效果。不过第三种方法在展开比较方便,日常练习中可以使用,但如果是在大型项目中还是推荐使用前两种方法。

    4. 命名空间补充知识

    4.1 命名空间里的内容既可以定义变量,也可以定义函数

    //1. 普通的命名空间
    namespace N1 // N1为命名空间的名称
    {
    	// 命名空间中的内容,既可以定义变量,也可以定义函数
    	int a;
    	int Add(int left, int right)
    	{
    		return left + right;
    	}
    }
    

    4.2 命名空间可以嵌套

    //2. 命名空间可以嵌套
    namespace N2
    {
    	int a;
    	int b;
    	int Add(int left, int right)
    	{
    		return left + right;
    	}
    	namespace N3
    	{
    		int c;
    		int d;
    		int Sub(int left, int right)
    		{
    			return left - right;
    		}
    	}
    }
    

    下面我们来看嵌套命名空间是如何来调用的:

    int main()
    {
    	printf("%d\n", N2::a);
    	printf("%d\n", N2::Add(3, 4));
    	printf("%d\n", N2::N3::c);
    }
    

    可以看到嵌套命名空间在展开的时候利用域作用限定符逐层展开即可。

    4.3 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。

    //3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
    
    //a.cpp
    namespace N1 // N1为命名空间的名称
    {
    	// 命名空间中的内容,既可以定义变量,也可以定义函数
    	int a;
    	int Add(int left, int right)
    	{
    		return left + right;
    	}
    }
    
    //b.cpp
    namespace N1
    {
    	int Mul(int left, int right)
    	{
    		return left * right;
    	}
    }
    

    命名空间的介绍到这里就全部结束了,学完命名空间之后大家一定也感受到它的优势了。再拿我最开始的例子来举例,当你和张三在命名变量的时候,你的变量就放在你的命名空间,张三的变量放在他的命名空间中。在项目汇总时,如果要用你的变量就从你的命名空间中取,用它的就从他的命名空间中取,这样就永远不会发生命名冲突了。

    最后希望这篇文章能够为大家带来帮助。

    展开全文
  • linux命名空间(namespace)学习(三)

    千次阅读 2018-12-08 11:09:40
    LinuxPID命名空间学习 通过对于前两节的学习我们知道Linux内核使用task_struct结构来表示和管理进程,这个数据结构里面存放了很多有关于PID如何管理的数据,可以这么说,Linux内核所有有关进程管理的数据结构都和此...

    LinuxPID命名空间学习

    通过对于前两节的学习我们知道Linux内核使用task_struct结构来表示和管理进程,这个数据结构里面存放了很多有关于PID如何管理的数据,可以这么说,Linux内核所有有关进程管理的数据结构都和此数据结构有关。该数据结构存放在include/linux/sched.h头文件里,并且这个数据结构比较大,就不一一列举了。实际上一一列举也没有什么意思,因这个数据结构过于庞大导致列举出来连笔者都感到头大----可以举出这么一个例子:这个数据结构占用内核1.7K的空间,可想有多么庞大。但是不需要担心,可以把此数据结构分块划分的话,就简单很多了。话不多说我会根据如下来结构体系来介绍:

     1. 进程类型
     2. PID的命名空间;
     3.管理 PID有关的数据结构
    

    进程类型

    进程如何划分呢?我们可以把进程划分为如下四种类型:

     1.普通PID:
     	这是Linux对于每一个进程都使用的划分,每一个进程都分配给一个PID,每一个PID都对应一个task_struct,每一个task_struct对应着相应的命名空间,和PID类型(先做了解)。
     2.TGID:
     	线程组ID,这个是线程的定义,这个定义在clone时候使用CLONE_THREAD函数调用的时候进行:在一个进程中,如果以CLONE_THREAD标志来调用clone建立的进程就是该进程的一个线程,它们处于一个线程组,该线程组的ID叫做TGID。处于相同的线程组中的所有进程都有相同的TGID;线程组组长的TGID与其PID相同;一个进程没有使用线程,则其TGID与PID也相同。
     3.PGID:
     	另外,独立的进程可以组成进程组(使用setpgrp系统调用),进程组可以简化向所有组内进程发送信号的操作,例如用管道连接的进程处在同一进程组内。进程组ID叫做PGID,进程组内的所有进程都有相同的PGID,等于该组组长的PID。
     4.SID:
     	几个进程组可以合并成一个会话组(使用setsid系统调用),可以用于终端程序设计。会话组中所有进程都有相同的SID。
    

    PID命名空间

    命名空间是为操作系统层面的虚拟化机制提供支撑,目前实现的有六种不同的命名空间,分别为mount命名空间、UTS命名空间、IPC命名空间、用户命名空间、PID命名空间、网络命名空间。命名空间简单来说提供的是对全局资源的一种抽象,将资源放到不同的容器中(不同的命名空间),各容器彼此隔离。命名空间有的还有层次关系,如PID命名空间,图1 为命名空间的层次关系图。

    图1 命名空间的层次关系
    在上图有四个命名空间,一个父命名空间衍生了两个子命名空间,其中的一个子命名空间又衍生了一个子命名空间。以PID命名空间为例,由于各个命名空间彼此隔离,所以每个命名空间都可以有 PID 号为 1 的进程;但又由于命名空间的层次性,父命名空间是知道子命名空间的存在,因此子命名空间要映射到父命名空间中去,因此上图中 level 1 中两个子命名空间的六个进程分别映射到其父命名空间的PID 号5~10。

    命名空间增大了 PID 管理的复杂性,对于某些进程可能有多个PID——在其自身命名空间的PID以及其父命名空间的PID,凡能看到该进程的命名空间都会为其分配一个PID。因此就有:

    全局ID:

    在内核本身和初始命名空间中具有唯一的ID表示唯一的进程。内核中的init进程就是初始命名空间。系统为每一个进程分配了ID号来标示不同的进程,无论是在一级命名空间还是在二级命名空间中的进程,都在初始命名空间进程中都申请了一个ID号用于管理。这样在父命名空间中就可以看到子命名空间中的进程了。
    

    局部ID

    也可以说是子命名空间中看到的ID号,这个ID只能在子命名空间中有用,在父命名空间中没有作用。
    

    进程ID管理数据结构

    Linux 内核在设计管理ID的数据结构时,要充分考虑以下因素:

    1.如何快速地根据进程的 task_struct、ID类型、命名空间找到局部ID
    2.如何快速地根据局部ID、命名空间、ID类型找到对应进程的 task_struct
    3.如何快速地给新进程在可见的命名空间内分配一个唯一的 PID
    如果将所有因素考虑到一起,将会很复杂,下面将会由简到繁设计该结构。
    介绍的结构如下:

     1. 一个PID只对应一个task_struct结构;
     2. 加入TGID/PGID/SID管理的PID管理;
     3. 加入命名空间的PID管理
    

    一个PID对应一个task_struct结构

    如果不考虑一个进程对应的TGID/PGID/SID,也不考虑一个进程对应的命名空间设计,我们可以对于进程的数据结构进行如下设计:
    一个进程对应了一个task_struct结构,其中每一个PID 中的nr表示PID号即为进程号,PID 结构中的pid_chain代表PID散列表的节点。
    进程的设计一

    上述设计核心思想如下:
    1.一个task_struct 中存放着pid_link结构体,指向struct pid结构。
    2.PID结构里面存放着PID 号(即为nr),也存放着指向pid_link的指针和PID散列表的节点的节点。
    3.每一个PID的申请和释放都是通过pid_hash(PID散列表)和pid_map来进行管理的。
    4.对于每一个PID的查找也是通过pid_hash来管理的;
    数据结构如下:

    struct task_struct {
        //...
        struct pid_link pids;
        //...
    };
    
    struct pid_link {
        struct hlist_node node;  
        struct pid *pid;          
    };
    
    struct pid {
        struct hlist_head tasks;        //指回 pid_link 的 node
        int nr;                       //PID
        struct hlist_node pid_chain;    //pid hash 散列表结点
    };
    

    上述两个主要的数据结构还有两个没有介绍:
    pid_hash[]:是PID的hash散列表,用于管理和查找pid结构,主要通过pid号来进行关键索引找到PID结构。然后找到task_struct结构,主要查找有一下四步:

     1. 通过PID号,索引pid_hash[],找到struct pid的pid_chain结构;
     2. 通过pid_chain找到struct pid结构;
     3. struct pid结构中有tasks指向,task_struct->plink.node;
     4. 通过container_of查找到struct task_struct结构;
    

    pid_map:PID位图表示,主要用于申请和释放未使用的PID号,这样不用遍历pid_hash结构也能够找到未使用的PID号。

    加入TGID/PGID/SID管理的PID管理

    加入TGID/PGID/SID管理的PID管理稍微比较复杂一点,在上述基础上我们知道struct pid结构可以索引到task_struct结构,但是如何加入TGID/PGID/SID的管理呢?可以从如下角度考虑下问题:

     1. 如何通过进程本身的task_struct 索引到自身的所属TGID/PGID/SID的struct PID 结构?
     2. 一个线程组或者一个进程组或者一个组里面的线程主ID或者进程组ID或者组ID怎么索引到其下所有的线程,进程,组中所有的进程?
    

    以上两点的解决方案如下图:

    加入TGID/PGID/SID管理的PID管理ruc
    对于上述的两点疑问可以做如下解答:

     1. 在task_struct结构里面增加struct pid_link数组到至少四个,第一个索引自身进程的struct pid结构,第二个索引线程组ID,第三个索引PGID,第四个索引SID。可以通过一次索引查询到自身task_struct的PID,TGID,PGID,SID结构的task_struct结构。
     2. 每一个自身的进程的PID结构把tasks数组增加至至少四个,第一个索引自身的task_struct ,第二个索引以自己为主进程的下面挂载多少个线程的task_struct,第三个索引以自己为主进程下面挂载多少个gid..... 其中hlist_head tasks[index]以struct task_struct->pid_link[index].hlist_node为节点.
    

    数据结构设计如下:

    enum pid_type
    {
        PIDTYPE_PID,
        PIDTYPE_PGID,
        PIDTYPE_SID,
        PIDTYPE_MAX
    };
    
    struct task_struct {
        //...
        pid_t pid;     //PID
        pid_t tgid;    //thread group id
    
        struct task_struct *group_leader;   // threadgroup leader
    
        struct pid_link pids[PIDTYPE_MAX];
    
        //...
    };
    
    struct pid_link {
        struct hlist_node node;  
        struct pid *pid;          
    };
    
    struct pid {
        struct hlist_head tasks[PIDTYPE_MAX];
        int nr;                         //PID
        struct hlist_node pid_chain;    // pid hash 散列表结点
    };
    

    **

    增加PID命名空间的PID表示结构

    **
    再回到PID命名空间的讨论范畴,通过本文中对于PID命名空间的介绍我们知道每一个命名空间中其PID分配是相对独立的,在父命名空间中可以看到子命名空间中的进程,父命名空间中看到的进程号是父命名空间分配的,子命名空间中看到的进程号是子命名空间分配的。
    可能会有一下疑问:

     1. 子命名空间中的进程怎么会索引到父命名空间中?
     2. 子命名空间中怎么会感知父命名空间的存在呢?
     3. 父命名空间如何会知道子命名空间中的进程呢?
     4. 父命名空间中的进程如何给子命名空间中的进程分配PID呢?
    

    为了回答以上问题,我们先从第四个问题开始讨论:
    为了使父命名空间给子命名空间中的进程分配进程号,Linux内核在命名空间设计中把pid_map结构放入到命名空间中结构,这样每一个父命名空间中的结构就能够给子命名空间中的进程分配ID了,如下所示:

    struct pid_namespace {
            struct kref kref;
            struct pidmap pidmap[PIDMAP_ENTRIES];
            int last_pid;
            struct task_struct *child_reaper;
            struct kmem_cache *pid_cachep;
            unsigned int level;
            struct pid_namespace *parent;
    #ifdef CONFIG_PROC_FS
            struct vfsmount *proc_mnt;
    #endif
    #ifdef CONFIG_BSD_PROCESS_ACCT
            struct bsd_acct_struct *bacct;
    #endif
    };
    以上数据结构还回答了我们第二个问题:子命名空间怎么感知父命名空间的存在
    

    父命名空间如何会知道子命名空间中的进程呢?

    我们知道同一个父命名空间中的进程ID和子命名空间中的ID互相不影响,而且敷命名空间的和子命名空间是不相同的,这样我们就可以在设计数据结构的时候把两者设计在一起,只要找到设计的数据结构就可以通过pid_hash得到struct upid结构。
    上面提到的pid_hash索引的功能有所变化,之前提交通过pid_hash表通过PID值可以索引到struct pid结构,但是现在我们通过hash表先索引到struct upid结构,再通过upid结构和namespace的level值所引到pid结构。进一步所引到task_struct结构
    如下所示:

    struct upid {
            /* Try to keep pid_chain in the same cacheline as nr for find_vpid */
            int nr;
            struct pid_namespace *ns;
            struct hlist_node pid_chain;
    };
    

    以下图片会帮助我们回答以上所有问题,举例来说,在level 2 的某个命名空间上新建了一个进程,分配给它的 pid 为45,映射到 level 1 的命名空间,分配给它的 pid 为 134;再映射到 level 0 的命名空间,分配给它的 pid 为289,对于这样的例子,如图4所示为其表示:在这里插入图片描述
    图中关于如果分配唯一的 PID 没有画出,但也是比较简单,与前面两种情形不同的是,这里分配唯一的 PID 是有命名空间的容器的,在PID命名空间内必须唯一,但各个命名空间之间不需要唯一。
    数据结构设计如下:

    struct pid
    {
        unsigned int level;  
        /* lists of tasks that use this pid */
        struct hlist_head tasks[PIDTYPE_MAX];
        struct upid numbers[1];
    };
    
    struct upid {
        int nr;
        struct pid_namespace *ns;
        struct hlist_node pid_chain;
    };
    
    

    以上摘自:https://www.cnblogs.com/hazir/p/linux_kernel_pid.html

    展开全文
  • 博主-草原飞歌刚开始编程的程序员在给unity项目写脚本的时候,看到自己新建好的一个类,...UseingXX表示导入某个命名空间。比如说usingSystem;就是到导入操作系统命名空间,usingUnityEngine;就是导入unity引擎程序...

    博主-草原飞歌

    刚开始编程的程序员在给unity项目写脚本的时候,看到自己新建好的一个类,系统会在脚本开头自动写入

    using System;

    using UnityEngine;

    ...

    这几行代码。比如

    这些代码在脚本中有什么作用呢?不写行不行?

    Useing XX表示导入某个命名空间。比如说using System;就是到导入操作系统命名空间,using UnityEngine;就是导入unity引擎程序的命名空间。高级语言总是依赖于许多系统或程序预定义的元素,如果在脚本开头导入预定义的元素,这样在自己的程序中就可以自由地使用这些元素。

    如果没有导入名字空间的话,程序还能正确运行吗?比如我们注释掉第一行

    马上看到MonoBehaviour,变红出错了。程序认为找不到自定义类Debug要继承的父类。但是如果我们改成这样,UnityEngine.MonoBehaviour,错误就消失了。在MonoBehaviour前面加上UnityEngine和连接符“.”,告诉程序MonoBehaviour来自UnityEngine命名空间,这样脚本就知道该去哪里找到这个类了。但是这样做的麻烦在于每次调用时都要写“命名空间.XX”,所以只要在脚本头一次导入,后面就省事多了。

    举例来看一下实际项目代码中常用到的命名空间:

    下面总结一下system常用的命名空间:

    System命名空间包含所有的基础类。

    using System.Collections;

    有ArrayList;Hashtable;Stack;Queue;DictionaryEntry;等集合

    using System.Reflection;

    获取Assembly 的属性值

    using System.Data;

    访问和操作数据库等类

    using System.Drawing;

    图像,画笔

    using System.IO;

    对文件、文件夹的操作

    using System.Media;

    播放wav和系统wav文件

    using System.Net;

    操作网络

    using System.Runtime;

    运行时的各种信息

    using System.Security;

    用于安全和加密

    using System.Text;

    各种编码方式和正则表达式

    using System.Threading;

    多线程

    .using System.Web;

    asp.net的web编程

    .using System.Windows.Forms;

    各种控件

    .using System.Xml;

    操作xml文件

    在unity官网可以看到UnityEngine命名空间的子目录,具体内容在写代码的时候查阅。

    展开全文
  • 1、什么是命名空间命名空间设计目的是提供一种让一组名称与其他名称分隔开的方式。在一个命名空间中声明的类的名称与另一个命名空间中声明...2、为什么要使用命名空间? 就像上面定义里说的, 在较大的项目中...
  • 摘要:学习TP,要涉及到PHP命名空间的问题,特将学习过程记录如下,给同样入门TP的人铺点路。
  • spring中的p命名空间就是为了更加方便的使用set方法注入属性内容 举例说明: User实体类 public class User { private String name; private int age; public String getName() { return name; } public ...
  • 详细解读php的命名空间(一)

    千次阅读 2017-12-22 17:23:53
    php的命名空间功能已经出来很久了,但是一直...一:命名空间概念:命名空间是一种封装事物的方法,类似于目录和文件。 命名空间解决的问题(手册上也写的很清楚,下面按照自己的理解简化了): 1:解决程序编写者自
  • std命名空间

    千次阅读 多人点赞 2019-05-15 19:05:00
    命名空间使用目的是为了将逻辑相关的标示符限定在一起,组成相应的命名空间,可使整个系统更加模块化,最重要的是它可以防止命名冲突。就好比在两个函数或类中定义相同名字的对象一样,利用作用域标示符限定该对象...
  • C++头文件和std命名空间

    千次阅读 2019-11-07 11:39:22
    C++是在C语言的基础上开发的,早期的 C++ 还不完善,不支持命名空间,没有自己的编译器,而是将 C++ 代码翻译成C代码,再通过C编译器完成编译。这个时候的 C++ 仍然在使用C语言的库,stdio.h、stdlib.h、string.h 等...
  • C++:命名空间(namespace)及其使用

    千次阅读 多人点赞 2019-01-08 17:17:02
    命名空间 在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染。 ...
  • XML 命名空间

    千次阅读 2018-11-23 23:30:20
    命名空间的作用 命名空间的作用是避免xml中元素命名的冲突。举例来说我们都可以定义自己的元素名,元素在一个xml文件里面它的含义是表格,在另一个xml文件里可以把它定义为桌子。示例如下代码:表格里可以有&...
  • Linux 网络命名空间

    千次阅读 2017-04-09 09:59:58
    网络命名空间 虚拟网络创建 iproute2 创建新的网络命名空间 显示所有的虚拟网络命名空间 进入虚拟网络环境 设置虚拟网络环境net0的veth0设备处于激活状态 为虚拟网络环境net0的veth0设备增加IP地址 连接两个网络环境...
  • namespace命名空间使用

    千次阅读 2018-08-01 10:04:27
    一、何为命名空间 PHP 命名空间(namespace)是在PHP 5.3中加入的。“什么是命名空间?从广义上来说,命名空间是一种封装事物的方法。在很多地方都可以见到这种抽象概念。例如,在操作系统中目录用来将相关文件分组...
  • 第三章:参数服务器、命名空间与动态配置参数一、参数服务器1. 概念2. 使用终端命令维护参数3. launch文件维护参数4. node 节点中维护参数4.1. roscpp的参数API4.2. rospy的参数API三、命名空间1. 概念2. 重映射3. ...
  • 使用命名空间、头文件和实现文件

    千次阅读 2016-03-03 12:19:14
    //至今没有解决的一个问题, 如a.cpp中有一个命名空间ming, 现在b.cpp想要使用这个命名空间, 或者使用该空间中的某一个类/普通函数/变量, 至今不知道怎么解决 //下面的方法是一种通用的正确方法 //自定义命名空间...
  • 学校的人事部门保存了有关学生的部分数据(学号、姓名、年龄、住址),教务部门也保存了学生的另外一些...要求用c++编程,使用命名空间。解:命名空间是用户命名的作用域,用来处理程序中常见的同名冲突。命名空间::
  • C++在命名空间中声明类和成员函数

    千次阅读 2018-06-24 15:47:22
    首先关于前置声明,有以下几点要注意:在b.h头文件中引入类a时,有两种方式,前置声明和 #include “a.h”,建议使用前置声明,当a.h的私有成员改变时,b.h不需要重新编译。... 其次关于命名空间:1、为什么引入...
  • C# 命名空间调用类、字符串

    千次阅读 2018-12-23 15:05:03
    代码和被使用的类在同一命名空间,则不用using。 在不同命名空间的类调用方法有两种: 一、 写全称:命名空间.类名 _01测试.测试 test = new _01测试.测试(); 二、 1.在解决方案中引用要调用的类的项目 2、在调用...
  • java命名空间与命名

    千次阅读 2016-10-12 17:11:50
     对于一个public类,它是可以被项目中任何一个类所引用的,只需在使用它前import一下它所对应的class文件即可。将类名与文件名一一对应就可以方便虚拟机  在相应的路径(包名)中找到相应的类的信息。如果不这么做的...
  • C++入门:命名空间,缺省参数,函数重载详解

    千次阅读 多人点赞 2022-04-27 19:43:25
    1. C++关键字(C++98) ... 又是什么东西呢,接下来由此引入命名冲突和命名空间关键字 namespace 命名冲突: 命名冲突:同一个作用域不能定义同名变量 -- C语言没有很好的解决这个问题,CPP引入n...
  • using namespace ::std //使用标准的命名空间命名空间是用来解决全局变量的命名冲突的问题。 这里写代码片 #include &lt;iostream&gt; using namespace ::std;//使用标准的命名空间 namespace one{...
  • TypeScript_命名空间(namespace)

    千次阅读 2020-03-04 17:24:28
    如果你发现自己写的功能(函数/类/接口等...)越来越多, 你想对他们进行分组管理就可以用命名空间, 下面先用"类"举例: namespace Tools { const TIMEOUT = 100; export class Ftp { constructor() { setTimeout...
  • 1.子命名空间定义 PHP提供了层次化的空间命名方式,类似于一个虚拟目录,tp5会自动加载该命名空间 namespace app1\pro1\item1; function func(){ echo "func1"; } const x = "name1"; 2.命名空间的三种访问方式 ...
  • C++基础篇--作用域和自定义命名空间

    千次阅读 2015-03-23 17:19:57
    新增的一个feature:用户自定义命名空间,也常被简称为命名空间 namespace ,为区别下文称前者为 generalized namespace(GNS). 后者 user defined namespace(UDNS )。举例:  int c; // ①  fun1()  ...
  • 默认情况下可以直接使用默认命名空间中的所有标识符。 举例说明: 强制类型转换 C方式强制类型转换存在的问题: 过于粗暴: 任意类型之间都可以进行转换,编译器很难判断其正确性。 难于...
  • 设置 C# 默认命名空间 为:SampleNamespace [csharp] view plaincopy namespace SampleNamespace  {   class SampleClass   {   public void SampleMethod()
  • 往期目录 第一课, 体验typescript ...如果你发现自己写的功能(函数/类/接口等...)越来越多, 你想对他们进行分组管理就可以用命名空间, 下面先用"类"举例: namespace Tools { const TIMEOUT = 100;...
  • 作为一个.NET程序员有必要对命名空间和程序集有明确的认识,下文很好解释了这两者的关系,感谢作者! 本文转自:http://www.cnblogs.com/netlyf/archive/2009/09/17/1568389.html  原作者:NetLYF 如果说命名...
  • WebService命名空间冲突

    千次阅读 2014-07-09 18:43:57
    举例来说,对于下面的WebService,如果类MyClass1, MyClass2, SubClass没有指定XML命名空间,都默认都是“http://tempuri.org/”,当然在本例中,是给类SubClass添加XML属性描述,同样,如果不给SubClass添加XML...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 69,023
精华内容 27,609
关键字:

命名空间的使用举例