1,Containers can run instructions native to the core CPU without any special interpretation mechanisms. None of the complexities of paravirtualization or system call thunking are required either.

2,By providing a way to create and enter containers, an operating system gives applications the illusion of running on a separate machine while at the same time sharing many of the underlying resources. For example, the page cache of common files—glibc for example—may effectively be shared because all containers use the same kernel and, depending on the container configuration, frequent the same libc library. This sharing can often extend to other files in directories that do not need to be written to.

3,资源包括 CPU(中央处理器)、内存、存储器和网络资源。

4,cgroup url http://www.ibm.com/developerworks/cn/linux/1404_caojh_lxc/

5,linux container tools url http://www.ibm.com/developerworks/linux/library/l-lxc-containers/ or http://www.ibm.com/developerworks/cn/linux/1404_caojh_lxc/

---------------------------------------------------------------------------

原文连接http://www.csdn123.c口m/html/topnews201408/63/3063.htm

Linux内核的namespace机制分析

1.  Linux内核namespace机制

Linux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于某个特定的Namespace。每个namespace下的资源对于其他namespace下的资源都是透明,不可见的。因此在操作系统层面上看,就会出现多个相同pid的进程。系统中可以同时存在两个进程号为0,1,2的进程,由于属于不同的namespace,所以它们之间并不冲突。而在用户层面上只能看到属于用户自己namespace下的资源,例如使用ps命令只能列出自己namespace下的进程。这样每个namespace看上去就像一个单独的Linux系统。

2 .  Linux内核中namespace结构体

在Linux内核中提供了多个namespace,其中包括fs (mount), uts, network, sysvipc, 等。一个进程可以属于多个namesapce,既然namespace和进程相关,那么在task_struct结构体中就会包含和namespace相关联的变量。在task_struct 结构中有一个指向namespace结构体的指针nsproxy。

struct task_struct {

……..

/* namespaces */

struct nsproxy *nsproxy;

…….

}

再看一下nsproxy是如何定义的,在include/linux/nsproxy.h文件中,这里一共定义了5个各自的命名空间结构体,在该结构体中定义了5个指向各个类型namespace的指针,由于多个进程可以使用同一个namespace,所以nsproxy可以共享使用,count字段是该结构的引用计数。

/* 'count' is the number of tasks holding a reference.

* The count for each namespace, then, will be the number

* of nsproxies pointing to it, not the number of tasks.

* The nsproxy is shared by tasks which share all namespaces.

* As soon as a single namespace is cloned or unshared, the

* nsproxy is copied

*/

struct nsproxy {

atomic_t count;

struct uts_namespace *uts_ns;

struct ipc_namespace *ipc_ns;

struct mnt_namespace *mnt_ns;

struct pid_namespace *pid_ns_for_children;

struct net             *net_ns;

};

(1)     UTS命名空间包含了运行内核的名称、版本、底层体系结构类型等信息。UTS是UNIX Timesharing System的简称。

(2)     保存在struct ipc_namespace中的所有与进程间通信(IPC)有关的信息。

(3)     已经装载的文件系统的视图,在struct mnt_namespace中给出。

(4)     有关进程ID的信息,由struct pid_namespace提供。

(5)     struct net_ns包含所有网络相关的命名空间参数。

系统中有一个默认的nsproxy,init_nsproxy,该结构在task初始化是也会被初始化。#define INIT_TASK(tsk)  \

{

.nsproxy   = &init_nsproxy,

}

其中init_nsproxy的定义为:

static struct kmem_cache *nsproxy_cachep;

struct nsproxy init_nsproxy = {

.count                         = ATOMIC_INIT(1),

.uts_ns                       = &init_uts_ns,

#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC)

.ipc_ns                        = &init_ipc_ns,

#endif

.mnt_ns                      = NULL,

.pid_ns_for_children        = &init_pid_ns,

#ifdef CONFIG_NET

.net_ns                       = &init_net,

#endif

};

对于         .mnt_ns   没有进行初始化,其余的namespace都进行了系统默认初始。

3. 使用clone创建自己的Namespace

如果要创建自己的命名空间,可以使用系统调用clone(),它在用户空间的原型为

int clone(int (*fn)(void *), void *child_stack, int flags, void *arg)

这里fn是函数指针,这个就是指向函数的指针,, child_stack是为子进程分配系统堆栈空间,flags就是标志用来描述你需要从父进程继承那些资源, arg就是传给子进程的参数也就是fn指向的函数参数。下面是flags可以取的值。这里只关心和namespace相关的参数。

CLONE_FS          子进程与父进程共享相同的文件系统,包括root、当前目录、umask

CLONE_NEWNS     当clone需要自己的命名空间时设置这个标志,不能同时设置CLONE_NEWS和CLONE_FS。

Clone()函数是在libc库中定义的一个封装函数,它负责建立新轻量级进程的堆栈并且调用对编程者隐藏了clone系统条用。实现clone()系统调用的sys_clone()服务例程并没有fn和arg参数。封装函数把fn指针存放在子进程堆栈的每个位置处,该位置就是该封装函数本身返回地址存放的位置。Arg指针正好存放在子进程堆栈中的fn的下面。当封装函数结束时,CPU从堆栈中取出返回地址,然后执行fn(arg)函数。

/* Prototype for the glibc wrapper function */

#include <sched.h>

int clone(int (*fn)(void *), void *child_stack,

int flags, void *arg, ...

/* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

/* Prototype for the raw system call */

long clone(unsigned long flags, void *child_stack,

void *ptid, void *ctid,

struct pt_regs *regs);

我们在Linux内核中看到的实现函数,是经过libc库进行封装过的,在Linux内核中的fork.c文件中,有下面的定义,最终调用的都是do_fork()函数。

#ifdef __ARCH_WANT_SYS_CLONE

#ifdef CONFIG_CLONE_BACKWARDS

SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,

int __user *, parent_tidptr,

int, tls_val,

int __user *, child_tidptr)

#elif defined(CONFIG_CLONE_BACKWARDS2)

SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,

int __user *, parent_tidptr,

int __user *, child_tidptr,

int, tls_val)

#elif defined(CONFIG_CLONE_BACKWARDS3)

SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,

int, stack_size,

int __user *, parent_tidptr,

int __user *, child_tidptr,

int, tls_val)

#else

SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,

int __user *, parent_tidptr,

int __user *, child_tidptr,

int, tls_val)

#endif

{

return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);

}

#endif

3.1  do_fork函数

在clone()函数中调用do_fork函数进行真正的处理,在do_fork函数中调用copy_process进程处理。

long do_fork(unsigned long clone_flags,

unsigned long stack_start,

unsigned long stack_size,

int __user *parent_tidptr,

int __user *child_tidptr)

{

struct task_struct *p;

int trace = 0;

long nr;

/*

* Determine whether and which event to report to ptracer.  When

* called from kernel_thread or CLONE_UNTRACED is explicitly

* requested, no event is reported; otherwise, report if the event

* for the type of forking is enabled.

*/

if (!(clone_flags & CLONE_UNTRACED)) {

if (clone_flags & CLONE_VFORK)

trace = PTRACE_EVENT_VFORK;

else if ((clone_flags & CSIGNAL) != SIGCHLD)

trace = PTRACE_EVENT_CLONE;

else

trace = PTRACE_EVENT_FORK;

if (likely(!ptrace_event_enabled(current, trace)))

trace = 0;

}

p = copy_process(clone_flags, stack_start, stack_size,

child_tidptr, NULL, trace);

/*

* Do this prior waking up the new thread - the thread pointer

* might get invalid after that point, if the thread exits quickly.

*/

if (!IS_ERR(p)) {

struct completion vfork;

struct pid *pid;

trace_sched_process_fork(current, p);

pid = get_task_pid(p, PIDTYPE_PID);

nr = pid_vnr(pid);

if (clone_flags & CLONE_PARENT_SETTID)

put_user(nr, parent_tidptr);

if (clone_flags & CLONE_VFORK) {

p->vfork_done = &vfork;

init_completion(&vfork);

get_task_struct(p);

}

wake_up_new_task(p);

/* forking complete and child started to run, tell ptracer */

if (unlikely(trace))

ptrace_event_pid(trace, pid);

if (clone_flags & CLONE_VFORK) {

if (!wait_for_vfork_done(p, &vfork))

ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);

}

put_pid(pid);

} else {

nr = PTR_ERR(p);

}

return nr;

}

3.2  copy_process函数

在copy_process函数中调用copy_namespaces函数。

static struct task_struct *copy_process(unsigned long clone_flags,

unsigned long stack_start,

unsigned long stack_size,

int __user *child_tidptr,

struct pid *pid,

int trace)

{

int retval;

struct task_struct *p;

/*下面的代码是对clone_flag标志进行检查,有部分表示是互斥的,例如CLONE_NEWNS和CLONENEW_FS*/

if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))

return ERR_PTR(-EINVAL);

if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS))

return ERR_PTR(-EINVAL);

if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND))

return ERR_PTR(-EINVAL);

if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM))

return ERR_PTR(-EINVAL);

if ((clone_flags & CLONE_PARENT) &&

current->signal->flags & SIGNAL_UNKILLABLE)

return ERR_PTR(-EINVAL);

……

retval = copy_namespaces(clone_flags, p);

if (retval)

goto bad_fork_cleanup_mm;

retval = copy_io(clone_flags, p);

if (retval)

goto bad_fork_cleanup_namespaces;

retval = copy_thread(clone_flags, stack_start, stack_size, p);

if (retval)

goto bad_fork_cleanup_io;

/*do_fork中调用copy_process函数,该函数中pid参数为NULL,所以这里的if判断是成立的。为进程所在的namespace分配pid,在3.0的内核之前还有一个关键函数,就是namespace创建后和cgroup的关系,

if (current->nsproxy != p->nsproxy) {

retval = ns_cgroup_clone(p, pid);

if (retval)

goto bad_fork_free_pid;

但在3.0内核以后给删掉了,具体请参考remove the ns_cgroup*/

if (pid != &init_struct_pid) {

retval = -ENOMEM;

pid = alloc_pid(p->nsproxy->pid_ns_for_children);

if (!pid)

goto bad_fork_cleanup_io;

}…..

}

3.3  copy_namespaces 函数

在kernel/nsproxy.c文件中定义了copy_namespaces函数。

int copy_namespaces(unsigned long flags, struct task_struct *tsk)

{

struct nsproxy *old_ns = tsk->nsproxy;

struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns);

struct nsproxy *new_ns;

/*首先检查flag,如果flag标志不是下面的五种之一,就会调用get_nsproxy对old_ns递减引用计数,然后直接返回0*/

if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |

CLONE_NEWPID | CLONE_NEWNET)))) {

get_nsproxy(old_ns);

return 0;

}

/*当前进程是否有超级用户的权限*/

if (!ns_capable(user_ns, CAP_SYS_ADMIN))

return -EPERM;

/*

* CLONE_NEWIPC must detach from the undolist: after switching

* to a new ipc namespace, the semaphore arrays from the old

* namespace are unreachable.  In clone parlance, CLONE_SYSVSEM

* means share undolist with parent, so we must forbid using

* it along with CLONE_NEWIPC.

对CLONE_NEWIPC进行特殊的判断,*/

if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) ==

(CLONE_NEWIPC | CLONE_SYSVSEM))

return -EINVAL;

/*为进程创建新的namespace*/

new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs);

if (IS_ERR(new_ns))

return  PTR_ERR(new_ns);

tsk->nsproxy = new_ns;

return 0;

}

3.4  create_new_namespaces函数

create_new_namespaces创建新的namespace

static struct nsproxy *create_new_namespaces(unsigned long flags,

struct task_struct *tsk, struct user_namespace *user_ns,

struct fs_struct *new_fs)

{

struct nsproxy *new_nsp;

int err;

/*为新的nsproxy分配内存空间,并对其引用计数设置为初始1*/

new_nsp = create_nsproxy();

if (!new_nsp)

return ERR_PTR(-ENOMEM);

/*如果Namespace中的各个标志位进行了设置,则会调用相应的namespace进行创建*/

new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs);

if (IS_ERR(new_nsp->mnt_ns)) {

err = PTR_ERR(new_nsp->mnt_ns);

goto out_ns;

}

new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns);

if (IS_ERR(new_nsp->uts_ns)) {

err = PTR_ERR(new_nsp->uts_ns);

goto out_uts;

}

new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns);

if (IS_ERR(new_nsp->ipc_ns)) {

err = PTR_ERR(new_nsp->ipc_ns);

goto out_ipc;

}

new_nsp->pid_ns_for_children =

copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children);

if (IS_ERR(new_nsp->pid_ns_for_children)) {

err = PTR_ERR(new_nsp->pid_ns_for_children);

goto out_pid;

}

new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);

if (IS_ERR(new_nsp->net_ns)) {

err = PTR_ERR(new_nsp->net_ns);

goto out_net;

}

return new_nsp;

out_net:

if (new_nsp->pid_ns_for_children)

put_pid_ns(new_nsp->pid_ns_for_children);

out_pid:

if (new_nsp->ipc_ns)

put_ipc_ns(new_nsp->ipc_ns);

out_ipc:

if (new_nsp->uts_ns)

put_uts_ns(new_nsp->uts_ns);

out_uts:

if (new_nsp->mnt_ns)

put_mnt_ns(new_nsp->mnt_ns);

out_ns:

kmem_cache_free(nsproxy_cachep, new_nsp);

return ERR_PTR(err);

}

3.4.1 create_nsproxy函数

static inline struct nsproxy *create_nsproxy(void)

{

struct nsproxy *nsproxy;

nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);

if (nsproxy)

atomic_set(&nsproxy->count, 1);

return nsproxy;

}

例子1:namespace pid的例子

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <unistd.h>

#include <sched.h>

#include <string.h>

static int fork_child(void *arg)

{

int a = (int)arg;

int i;

pid_t pid;

char *cmd  = "ps -el;

printf("In the container, my pid is: %d\n", getpid());

/*ps命令是解析procfs的内容得到结果的,而procfs根目录的进程pid目录是基于mount当时的pid namespace的,这个在procfs的get_sb回调中体现的。因此只需要重新mount一下proc, mount -t proc proc /proc*/

mount("proc", "/proc", "proc", 0, "");

for (i = 0; i <a; i++) {

pid = fork();

if (pid <0)

return pid;

else if (pid)

printf("pid of my child is %d\n", pid);

else if (pid == 0) {

sleep(30);

exit(0);

}

}

execl("/bin/bash", "/bin/bash","-c",cmd, NULL);

return 0;

}

int main(int argc, char *argv[])

{

int cpid;

void *childstack, *stack;

int flags;

int ret = 0;

int stacksize = getpagesize() * 4;

if (argc != 2) {

fprintf(stderr, "Wrong usage.\n");

return -1;

}

stack = malloc(stacksize);

if(stack == NULL)

{

return -1;

}

printf("Out of the container, my pid is: %d\n", getpid());

childstack = stack + stacksize;

flags = CLONE_NEWPID | CLONE_NEWNS;

cpid = clone(fork_child, childstack, flags, (void *)atoi(argv[1]));

printf("cpid: %d\n", cpid);

if (cpid <0) {

perror("clone");

ret = -1;

goto out;

}

fprintf(stderr, "Parent sleeping 20 seconds\n");

sleep(20);

ret = 0;

out:

free(stack);

return ret;

}

}运行结果:

root@ubuntu:~/c_program# ./namespace 7

Out of the container, my pid is: 8684

cpid: 8685

Parent sleeping 20 seconds

In the container, my pid is: 1

pid of my child is 2

pid of my child is 3

pid of my child is 4

pid of my child is 5

pid of my child is 6

pid of my child is 7

pid of my child is 8

F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD

4 R     0     1     0  0  80   0 -  1085 -      pts/0    00:00:00 ps

1 S     0     2     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

1 S     0     3     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

1 S     0     4     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

1 S     0     5     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

1 S     0     6     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

1 S     0     7     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

1 S     0     8     1  0  80   0 -   458 hrtime pts/0    00:00:00 namespace

例子2:UTS的例子

#define _GNU_SOURCE

#include <sys/wait.h>

#include <sys/utsname.h>

#include <sched.h>

#include <string.h>

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \

} while (0)

static int              /* Start function for cloned child */

childFunc(void *arg)

{

struct utsname uts;

/* Change hostname in UTS namespace of child */

if (sethostname(arg, strlen(arg)) == -1)

errExit("sethostname");

/* Retrieve and display hostname */

if (uname(&uts) == -1)

errExit("uname");

printf("uts.nodename in child:  %s\n", uts.nodename);

/* Keep the namespace open for a while, by sleeping.

*               This allows some experimentation--for example, another

*                             process might join the namespace. */

sleep(200);

return 0;           /* Child terminates now */

}

#define STACK_SIZE (1024 * 1024)    /* Stack size for cloned child */

int

main(int argc, char *argv[])

{

char *stack;                    /* Start of stack buffer */

char *stackTop;                 /* End of stack buffer */

pid_t pid;

struct utsname uts;

if (argc < 2) {

fprintf(stderr, "Usage: %s <child-hostname>\n", argv[0]);

exit(EXIT_SUCCESS);

}

/* Allocate stack for child */

stack = malloc(STACK_SIZE);

if (stack == NULL)

errExit("malloc");

stackTop = stack + STACK_SIZE;  /* Assume stack grows downward */

/* Create child that has its own UTS namespace;

*               child commences execution in childFunc() */

pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);

if (pid == -1)

errExit("clone");

printf("clone() returned %ld\n", (long) pid);

/* Parent falls through to here */

sleep(1);           /* Give child time to change its hostname */

/* Display hostname in parent's UTS namespace. This will be

*               different from hostname in child's UTS namespace. */

if (uname(&uts) == -1)

errExit("uname");

printf("uts.nodename in parent: %s\n", uts.nodename);

if (waitpid(pid, NULL, 0) == -1)    /* Wait for child */

errExit("waitpid");

printf("child has terminated\n");

exit(EXIT_SUCCESS);

}

root@ubuntu:~/c_program# ./namespace_1 test

clone() returned 4101

uts.nodename in child:  test

uts.nodename in parent: ubuntu

对于网络命名空间可以参考:

http://www.opencloudblog.com/?p=42

http://wenx05124561.blog.163.com/blog/static/124000805201311250241189/

http://man7.org/linux/man-pages/man2/clone.2.html

linix container & cgroup note的更多相关文章

  1. CGroup 介绍、应用实例及原理描述

    CGroup 介绍 CGroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制.记录.隔离进程组 (process groups) 所使用的物力资源 (如 cpu ...

  2. CGroup 介绍、应用实例及原理描述【转】

    转自:https://www.cnblogs.com/caoxiaojian/p/5633430.html CGroup 介绍 CGroup 是 Control Groups 的缩写,是 Linux ...

  3. Docker Remote API v1.24

    1. Brief introduction The Remote API has replaced rcli. The daemon listens on unix:///var/run/docker ...

  4. java中的重绘

    void java.awt.Container.validate()Validates this container and all of its subcomponents.这个函数更新容器及其全部 ...

  5. docker offical docs:Working with Containers

    enough ---------------------------------------------------------------------------------- Working wi ...

  6. .net文件压缩和解压及中文文件夹名称乱码问题

    /**************************注释区域内为引用http://www.cnblogs.com/zhaozhan/archive/2012/05/28/2520701.html的博 ...

  7. C#- 压缩和解压缩的研究 .

    用了第二种方法,感觉很不错,其他都没用过了.摘录下来,做一个备忘. 最近在网上查了一下在.net中进行压缩和解压缩的方法,方法有很多,我找到了以下几种: 1.利用.net自带的压缩和解压缩方法GZip ...

  8. .net中压缩和解压缩的处理

    最近在网上查了一下在.net中进行压缩和解压缩的方法,方法有很多,我找到了以下几种: 1.利用.net自带的压缩和解压缩方法GZip 参考代码如下: //======================= ...

  9. Kendo UI开发教程(9): Kendo UI Validator 概述

    Kendo UI Validator 支持了客户端校验的便捷方法,它基于HTML 5 的表单校验功能,支持很多内置的校验规则,同时也提供了自定义规则的便捷方法. 完整的Kendo UI 的Valida ...

随机推荐

  1. linux里的进程简介

    /sbin/init         内核启动的第一个用户级进程,引导用户空间服务    [kthreadd]         内核线程管理[migration/0]      用于进程在不同的CPU ...

  2. P1018 乘积最大

    开始定义状态f[i][j][k]为[i,j)区间插入k个括号,使用记忆化搜索,但是成功爆栈,得到4个mle #include <bits/stdc++.h> using namespace ...

  3. RESTful 架构理解

    REST中的关键词: 1.资源 2.资源的表述 3.状态转移 资源: "资源",可以是一段文本.一张图片.一首歌曲.一种操作.你可以用一个URI(统一资源定位符)指向它,每种资源对 ...

  4. linux ntp时间同步

    linux ntp时间同步 一.搭建时间同步服务器1.编译安装ntp serverrpm -qa | grep ntp若没有找到,则说明没有安装ntp包,从光盘上找到ntp包,使用rpm -Uvh n ...

  5. 异常处理与MiniDump详解(4) MiniDump

    http://blog.csdn.net/vagrxie/article/details/4398721 异常处理与MiniDump详解(4) MiniDump 分类:             [Wi ...

  6. 关于使用注解出现BeanCreationException或者NameNotFoundException的解决方法

    网上大部分解决方法是修改配置文件,但是本人修改后发现还是报错,只能耐着头皮继续看下去,最后发现是path出错,注意web.xml中的<resource-ref>的<res-ref-n ...

  7. c语言学习感想

    接触c语言已经2个多月了,在这段期间按时的完成了作业,上课能够较好的听讲,因此我获得了老师奖励的小黄衫. 同时,希望自己能够学好c语言! 学习感受与心得 因为兴趣,选择了计算机这专业,我从遥远的南方来 ...

  8. Java高级之虚拟机加载机制

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 1.0版本:2016-05-21 SubClass!! 执行结果说明一个问题:子类调用父类变量的时候 ...

  9. 小易邀请你玩一个数字游戏,小易给你一系列的整数。你们俩使用这些整数玩游戏。每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字。 例如: 如果{2,1,2,7}是你有的一系列数,小易说的数字是11.你可以得到方案2+2+7 = 11.如果顽皮的小易想坑你,他说的数字是6,那么你没有办法拼凑出和为6 现在小易给你n个数,让你找出无法从n个数中选取部分求和

    小易邀请你玩一个数字游戏,小易给你一系列的整数.你们俩使用这些整数玩游戏.每次小易会任意说一个数字出来,然后你需要从这一系列数字中选取一部分出来让它们的和等于小易所说的数字. 例如: 如果{2,1,2 ...

  10. mysql integer size 大小

    I was always wondering what the size of numeric columns in MySQL was. Forgive me if this is obvious ...