iis服务器助手广告广告
返回顶部
首页 > 资讯 > 操作系统 >linux中0号进程的含义是什么
  • 134
分享到

linux中0号进程的含义是什么

2023-07-05 13:07:11 134人浏览 安东尼
摘要

这篇文章主要介绍“linux中0号进程的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux中0号进程的含义是什么”文章能帮助大家解决问题。在linux中,0号进程是指idle进程,是

这篇文章主要介绍“linux中0号进程的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux中0号进程的含义是什么”文章能帮助大家解决问题。

在linux中,0号进程是指idle进程,是linux启动的第一个进程;它的task_struct的comm字段为“swapper”,所以也称为swpper进程。0号进程是唯一一个没有通过fork或者kernel_thread产生的进程,因为init_task是静态变量(初始化了的全局变量),其他进程的PCB都是fork或者kernel_thread动态申请内存创建的。

一、0号进程

0号进程,通常也被称为idle进程,或者也称为swapper进程。

每个进程都有一个进程控制块PCB(Process Control Block),PCB的数据结构类型是struct task_struct。idle进程对应的PCB是 struct task_struct init_task。

idle进程是唯一一个没有通过fork或者kernel_thread产生的进程,因为 init_task 是静态变量(初始化了的全局变量),其他进程的PCB都是fork或者kernel_thread动态申请内存创建的。

每个进程都有对应的一个函数,idle进程的函数是 start_kernel(),因为进入该函数前,栈指针SP已经指向 init_task 的栈顶了,处于什么进程,看SP指向哪个进程的栈。

0号进程是linux启动的第一个进程,它的task_struct的comm字段为"swapper",所以也称为swpper进程。

#define INIT_TASK_COMM "swapper"

当系统中所有的进程起来后,0号进程也就蜕化为idle进程,当一个core上没有任务可运行时就会去运行idle进程。一旦运行idle进程则此core就可以进入低功耗模式了,在ARM上就是WFI。

我们本节重点关注是0号进程是如何启动的。在linux内核中为0号进程专门定义了一个静态的task_struct的结构,称为init_task。

struct task_struct init_task= {#ifdef CONFIG_THREAD_INFO_IN_TASK    .thread_info    = INIT_THREAD_INFO(init_task),    .stack_refcount    = ATOMIC_INIT(1),#endif    .state        = 0,    .stack        = init_stack,    .usage        = ATOMIC_INIT(2),    .flags        = PF_KTHREAD,    .prio        = MAX_PRIO - 20,    .static_prio    = MAX_PRIO - 20,    .nORMal_prio    = MAX_PRIO - 20,    .policy        = SCHED_NORMAL,    .cpus_allowed    = CPU_MASK_ALL,    .nr_cpus_allowed= NR_CPUS,    .mm        = NULL,    .active_mm    = &init_mm,    .tasks        = LIST_HEAD_INIT(init_task.tasks),    .ptraced    = LIST_HEAD_INIT(init_task.ptraced),    .ptrace_entry    = LIST_HEAD_INIT(init_task.ptrace_entry),    .real_parent    = &init_task,    .parent        = &init_task,    .children    = LIST_HEAD_INIT(init_task.children),    .sibling    = LIST_HEAD_INIT(init_task.sibling),    .group_leader    = &init_task,    RCU_POINTER_INITIALIZER(real_cred, &init_cred),    RCU_POINTER_INITIALIZER(cred, &init_cred),    .comm        = INIT_TASK_COMM,    .thread        = INIT_THREAD,    .fs        = &init_fs,    .files        = &init_files,    .signal        = &init_signals,    .sighand    = &init_sighand,    .blocked    = {{0}},    .alloc_lock    = __SPIN_LOCK_UNLOCKED(init_task.alloc_lock),    .journal_info    = NULL,    INIT_CPU_TIMERS(init_task)    .pi_lock    = __RAW_SPIN_LOCK_UNLOCKED(init_task.pi_lock),    .timer_slack_ns = 50000,     .thread_pid    = &init_struct_pid,    .thread_group    = LIST_HEAD_INIT(init_task.thread_group),    .thread_node    = LIST_HEAD_INIT(init_signals.thread_head),};EXPORT_SYMBOL(init_task);

这个结构体中的成员都是静态定义了,为了简单说明,对这个结构做了简单的删减。同时我们只关注这个结构中的以下几个字段,别的先不关注。

  • .thread_info = INIT_THREAD_INFO(init_task), 这个结构在thread_info和内核栈的关系中有详细的描述

  • .stack = init_stack, init_stack就是内核栈的静态的定义

  • .comm = INIT_TASK_COMM, 0号进程的名称。

在这么thread_info和stack都涉及到了Init_stack, 所以先看下init_stack在哪里设置的。

最终发现init_task是在链接脚本中定义的。

#define INIT_TASK_DATA(align)                        \    . = ALIGN(align);                        \    __start_init_task = .;                        \    init_thread_uNIOn = .;                        \    init_stack = .;                            \    KEEP(*(.data..init_task))                    \    KEEP(*(.data..init_thread_info))                \    . = __start_init_task + THREAD_SIZE;                \    __end_init_task = .;

在链接脚本中定义了一个INIT_TASK_DATA的宏。

其中__start_init_task就是0号进程的内核栈的基地址,当然了init_thread_union=init_task=__start_init_task的。

而0号进程的内核栈的结束地址等于__start_init_task + THREAD_SIZE, THREAD_SIZE的大小在ARM64一般是16K,或者32K。则__end_init_task就是0号进程的内核栈的结束地址。

idle进程由系统自动创建, 运行在内核态,idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变为进程调度、交换。

二、Linux内核的启动

熟悉linux内核的朋友都知道,linux内核的启动 ,一般都是有bootloader来完成装载,bootloader中会做一些硬件的初始化,然后会跳转到linux内核的运行地址上去。

如果熟悉ARM架构的盆友也清楚,ARM64架构分为EL0, EL1, EL2, EL3。正常的启动一般是从高特权模式向低特权模式启动的。通常来说ARM64是先运行EL3,再EL2,然后从EL2就trap到EL1,也就是我们的Linux内核。

我们来看下Linux内核启动的代码。

代码路径:arch/arm64/kernel/head.S文件中

    ENTRY(stext)    bl    preserve_boot_args    bl    el2_setup            // Drop to EL1, w0=cpu_boot_mode    adrp    x23, __PHYS_OFFSET    and    x23, x23, MIN_KIMG_ALIGN - 1    // KASLR offset, defaults to 0    bl    set_cpu_boot_mode_flag    bl    __create_page_tables        bl    __cpu_setup            // initialise processor    b    __primary_switchENDPROC(stext)

上面就是内核在调用start_kernel之前做的主要工作了。

preserve_boot_args用来保留bootloader传递的参数,比如ARM上通常的dtb的地址

el2_setup:从注释上来看是, 用来trap到EL1,说明我们在运行此指令前还在EL2

__create_page_tables: 用来创建页表,linux才有的是页面管理物理内存的,在使用虚拟地址之前需要设置好页面,然后会打开MMU。目前还是运行在物理地址上的

__primary_switch: 主要任务是完成MMU的打开工作

__primary_switch:
   adrp    x1, init_pg_dir
   bl    __enable_mmu
   ldr    x8, =__primary_switched
   adrp    x0, __PHYS_OFFSET
   br    x8
ENDPROC(__primary_switch)

主要是调用__enable_mmu来打开mmu,之后我们访问的就是虚拟地址了

调用__primary_switched来设置0号进程的运行内核栈,然后调用start_kernel函数

__primary_switched:    adrp    x4, init_thread_union    add    sp, x4, #THREAD_SIZE    adr_l    x5, init_task    msr    sp_el0, x5            // Save thread_info    adr_l    x8, vectors            // load VBAR_EL1 with virtual    msr    vbar_el1, x8            // vector table address    isb    stp    xzr, x30, [sp, #-16]!    mov    x29, sp    str_l    x21, __fdt_pointer, x5        // Save FDT pointer    ldr_l    x4, kimage_vaddr        // Save the offset between    sub    x4, x4, x0            // the kernel virtual and    str_l    x4, kimage_voffset, x5        // physical mappings    // Clear BSS    adr_l    x0, __bss_start    mov    x1, xzr    adr_l    x2, __bss_stop    sub    x2, x2, x0    bl    __pi_memset    dsb    ishst                // Make zero page visible to PTW    add    sp, sp, #16    mov    x29, #0    mov    x30, #0    b    start_kernelENDPROC(__primary_switched)

init_thread_union就是我们在链接脚本中定义的,也就是0号进程的内核栈的栈底

add sp, x4, #THREAD_SIZE: 设置堆栈指针SP的值,就是内核栈的栈底+THREAD_SIZE的大小。现在SP指到了内核栈的顶端

最终通过b start_kernel就跳转到我们熟悉的linux内核入口处了。  至此0号进程就已经运行起来了。

三、1号进程

3.1 1号进程的创建

  当一条b start_kernel指令运行后,内核就开始的内核的全面初始化操作。

asmlinkage __visible void __init start_kernel(void){    char *command_line;    char *after_dashes;    set_task_stack_end_magic(&init_task);    smp_setup_processor_id();    debug_objects_early_init();    cgroup_init_early();    local_irq_disable();    early_boot_irqs_disabled = true;        boot_cpu_init();    page_address_init();    pr_notice("%s", linux_banner);    setup_arch(&command_line);        add_latent_entropy();    add_device_randomness(command_line, strlen(command_line));    boot_init_stack_canary();    mm_init_cpumask(&init_mm);    setup_command_line(command_line);    setup_nr_cpu_ids();    setup_per_cpu_areas();    smp_prepare_boot_cpu();        boot_cpu_hotplug_init();    build_all_zonelists(NULL);    page_alloc_init();    。。。。。。。    acpi_subsystem_init();    arch_post_acpi_subsys_init();    sfi_init_late();        arch_call_rest_init();}void __init __weak arch_call_rest_init(void){    rest_init();}

start_kernel函数就是内核各个重要子系统的初始化,比如mm, cpu, sched, irq等等。最后会调用一个rest_init剩余部分初始化,start_kernel在其最后一个函数rest_init的调用中,会通过kernel_thread来生成一个内核进程,后者则会在新进程环境下调 用kernel_init函数,kernel_init一个让人感兴趣的地方在于它会调用run_init_process来执行根文件系统下的 /sbin/init等程序。

noinline void __ref rest_init(void){    struct task_struct *tsk;    int pid;    rcu_scheduler_starting();        pid = kernel_thread(kernel_init, NULL, CLONE_FS);        rcu_read_lock();    tsk = find_task_by_pid_ns(pid, &init_pid_ns);    set_cpus_allowed_ptr(tsk, cpumask_of(smp_processor_id()));    rcu_read_unlock();    numa_default_policy();    pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);    rcu_read_lock();    kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);    rcu_read_unlock();        system_state = SYSTEM_SCHEDULING;    complete(&kthreadd_done);}

在这个rest_init函数中我们只关系两点:

  • pid = kernel_thread(kernel_init, NULL, CLONE_FS);

  • pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);


pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
   return _do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
       (unsigned long)arg, NULL, NULL, 0);
}

  很明显这是创建了两个内核线程,而kernel_thread最终会调用do_fork根据参数的不同来创建一个进程或者内核线程。关系do_fork的实现我们在后面会做详细的介绍。当内核线程创建成功后就会调用设置的回调函数。

  当kernel_thread(kernel_init)成功返回后,就会调用kernel_init内核线程,其实这时候1号进程已经产生了。1号进程的执行函数就是kernel_init, 这个函数被定义init/main.c中,接下来看下kernel_init主要做什么事情。

static int __ref kernel_init(void *unused){    int ret;    kernel_init_freeable();        async_synchronize_full();    ftrace_free_init_mem();    free_initmem();    mark_readonly();        pti_finalize();    system_state = SYSTEM_RUNNING;    numa_default_policy();    rcu_end_inkernel_boot();    if (ramdisk_execute_command) {        ret = run_init_process(ramdisk_execute_command);        if (!ret)            return 0;        pr_err("Failed to execute %s (error %d)\n",               ramdisk_execute_command, ret);    }        if (execute_command) {        ret = run_init_process(execute_command);        if (!ret)            return 0;        panic("Requested init %s failed (error %d).",              execute_command, ret);    }    if (!try_to_run_init_process("/sbin/init") ||        !try_to_run_init_process("/etc/init") ||        !try_to_run_init_process("/bin/init") ||        !try_to_run_init_process("/bin/sh"))        return 0;    panic("No working init found.  Try passing init= option to kernel. "          "See Linux Documentation/admin-guide/init.rst for guidance.");}

  • kernel_init_freeable函数中就会做各种外设驱动的初始化。

  • 最主要的工作就是通过execve执行/init可以执行文件。它按照配置文件/etc/initab的要求,完成系统启动工作,创建编号为1号、2号...的若干终端注册进程getty。每个getty进程设置其进程组标识号,并监视配置到系统终端的接口线路。当检测到来自终端的连接信号时,getty进程将通过函数execve()执行注册程序login,此时用户就可输入注册名和密码进入登录过程,如果成功,由login程序再通过函数execv()执行shell,该shell进程接收getty进程的pid,取代原来的getty进程。再由shell直接或间接地产生其他进程。

我们通常将init称为1号进程,其实在刚才kernel_init的时候1号线程已经创建成功,也可以理解kernel_init是1号进程的内核态,而我们所熟知的init进程是用户态的,调用execve函数之前属于内核态,调用之后就属于用户态了,执行的代码段与0号进程不在一样。

1号内核线程负责执行内核的部分初始化工作及进行系统配置,并创建若干个用于高速缓存和虚拟主存管理的内核线程。

至此1号进程就完美的创建成功了,而且也成功执行了init可执行文件。  

3.2 init进程

  随后,1号进程调用do_execve运行可执行程序init,并演变成用户态1号进程,即init进程。

  init进程是linux内核启动的第一个用户级进程。init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程。

  它按照配置文件/etc/initab的要求,完成系统启动工作,创建编号为1号、2号…的若干终端注册进程getty。

  每个getty进程设置其进程组标识号,并监视配置到系统终端的接口线路。当检测到来自终端的连接信号时,getty进程将通过函数do_execve()执行注册程序login,此时用户就可输入注册名和密码进入登录过程,如果成功,由login程序再通过函数execv()执行shell,该shell进程接收getty进程的pid,取代原来的getty进程。再由shell直接或间接地产生其他进程。

  上述过程可描述为:0号进程->1号内核进程->1号用户进程(init进程)->getty进程->shell进程

  注意,上述过程描述中提到:1号内核进程调用执行init函数并演变成1号用户态进程(init进程),这里前者是init是函数,后者是进程。两者容易混淆,区别如下:

  • kernel_init函数在内核态运行,是内核代码

  • init进程是内核启动并运行的第一个用户进程,运行在用户态下。

  • 一号内核进程调用execve()从文件/etc/inittab中加载可执行程序init并执行,这个过程并没有使用调用do_fork(),因此两个进程都是1号进程。

  当内核启动了自己之后(已被装入内存、已经开始运行、已经初始化了所有的设备驱动程序和数据结构等等),通过启动用户级程序init来完成引导进程的内核部分。因此,init总是第一个进程(它的进程号总是1)。

  当init开始运行,它通过执行一些管理任务来结束引导进程,例如检查文件系统、清理/tmp、启动各种服务以及为每个终端和虚拟控制台启动getty,在这些地方用户将登录系统。

  在系统完全起来之后,init为每个用户已退出的终端重启getty(这样下一个用户就可以登录)。init同样也收集孤立的进程:当一个进程启动了一个子进程并且在子进程之前终止了,这个子进程立刻成为init的子进程。对于各种技术方面的原因来说这是很重要的,知道这些也是有好处的,因为这便于理解进程列表和进程树图。init的变种很少。绝大多数Linux发行版本使用sysinit(由Miguel van Smoorenburg著),它是基于System V的init设计。UNIX的BSD版本有一个不同的init。最主要的不同在于运行级别:System V有而BSD没有(至少是传统上说)。这种区别并不是主要的。在此我们仅讨论sysvinit。 配置init以启动getty:/etc/inittab文件。

3.3 init程序

  1号进程通过execve执行init程序来进入用户空间,成为init进程,那么这个init在哪里呢

  内核在几个位置上来查寻init,这几个位置以前常用来放置init,但是init的最适当的位置(在Linux系统上)是/sbin/init。如果内核没有找到init,它就会试着运行/bin/sh,如果还是失败了,那么系统的启动就宣告失败了。

  因此init程序是一个可以又用户编写的进程, 如果希望看init程序源码的朋友,可以参见。

init包说明
sysvinit

早期一些版本使用的初始化进程工具, 目前在逐渐淡出linux历史舞台, sysvinit 就是 system V 风格的 init 系统,顾名思义,它源于 System V 系列 UNIX。它提供了比 BSD 风格 init 系统更高的灵活性。是已经风行了几十年的 UNIX init 系统,一直被各类 Linux 发行版所采用。

upstartdebian, ubuntu等系统使用的initdaemon
systemdSystemd 是 Linux 系统中最新的初始化系统(init),它主要的设计目标是克服 sysvinit 固有的缺点,提高系统的启动速度

  Ubuntu等使用deb包的系统可以通过dpkg -S查看程序所在的包

linux中0号进程的含义是什么

  Centos等使用rpm包的系统可以通过rpm -qf查看系统程序所在的包

linux中0号进程的含义是什么

linux中0号进程的含义是什么

四、2号进程

2号进程,也是由0号进程创建的。而且2号进程是所有内核线程父进程。

2号进程就是刚才rest_init中创建的另外一个内核线程。kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);

当kernel_thread(kthreadd)返回时,2号进程已经创建成功了。而且会回调kthreadd函数。

int kthreadd(void *unused){    struct task_struct *tsk = current;        set_task_comm(tsk, "kthreadd");    ignore_signals(tsk);    set_cpus_allowed_ptr(tsk, cpu_all_mask);    set_mems_allowed(node_states[N_MEMORY]);    current->flags |= PF_NOFREEZE;    cgroup_init_kthreadd();    for (;;) {        set_current_state(TASK_INTERRUPTIBLE);        if (list_empty(&kthread_create_list))            schedule();        __set_current_state(TASK_RUNNING);        spin_lock(&kthread_create_lock);        while (!list_empty(&kthread_create_list)) {            struct kthread_create_info *create;            create = list_entry(kthread_create_list.next,                        struct kthread_create_info, list);            list_del_init(&create->list);            spin_unlock(&kthread_create_lock);            create_kthread(create);            spin_lock(&kthread_create_lock);        }        spin_unlock(&kthread_create_lock);    }    return 0;}

这段代码大概的意思也很简单明显;

    • 设置当前进程的名字为"kthreadd",也就是task_struct的comm字段

    • 然后就是while循环,设置当前的进程的状态是TASK_INTERRUPTIBLE是可以中断的

    • 判断kthread_create_list链表是不是空,如果是空则就调度出去,让出cpu

    • 如果不是空,则从链表中取出一个,然后调用kthread_create去创建一个内核线程。

    • 所以说所有的内核线程的父进程都是2号进程,也就是kthreadd。

五、总结

linux启动的第一个进程是0号进程,是静态创建的,称为idle进程或者swapper进程。

在0号进程启动后会接连创建两个进程,分别是1号进程和2和进程。

1号进程最终会使用execve函数去调用可init可执行文件,init进程最终会去创建所有的应用进程,所以被称为inti进程。

2号进程会在内核中负责创建所有的内核线程,被称为kthreadd进程。

所以说0号进程是1号和2号进程的父进程;1号进程是所有用户态进程的父进程;2号进程是所有内核线程的父进程。

我们通过ps命令就可以详细的观察到这一现象。

root@ubuntu:zhuxl$ ps -eFUID         PID   PPID  C    SZ   RSS PSR STIME TTY          TIME CMDroot          1      0  0 56317  5936   2 Feb16 ?        00:00:04 /sbin/initroot          2      0  0     0     0   1 Feb16 ?        00:00:00 [kthreadd]

上面很清晰的显示:PID=1的进程是init,PID=2的进程是kthreadd。而他们俩的父进程PPID=0,也就是0号进程。

UID         PID   PPID  C    SZ   RSS PSR STIME TTY          TIME CMDroot          4      2  0     0     0   0 Feb16 ?        00:00:00 [kworker/0:0H]root          6      2  0     0     0   0 Feb16 ?        00:00:00 [mm_percpu_wq]root          7      2  0     0     0   0 Feb16 ?        00:00:10 [ksoftirqd/0]root          8      2  0     0     0   1 Feb16 ?        00:02:11 [rcu_sched]root          9      2  0     0     0   0 Feb16 ?        00:00:00 [rcu_bh]root         10      2  0     0     0   0 Feb16 ?        00:00:00 [migration/0]root         11      2  0     0     0   0 Feb16 ?        00:00:00 [watchdog/0]root         12      2  0     0     0   0 Feb16 ?        00:00:00 [cpuhp/0]root         13      2  0     0     0   1 Feb16 ?        00:00:00 [cpuhp/1]root         14      2  0     0     0   1 Feb16 ?        00:00:00 [watchdog/1]root         15      2  0     0     0   1 Feb16 ?        00:00:00 [migration/1]root         16      2  0     0     0   1 Feb16 ?        00:00:11 [ksoftirqd/1]root         18      2  0     0     0   1 Feb16 ?        00:00:00 [kworker/1:0H]root         19      2  0     0     0   2 Feb16 ?        00:00:00 [cpuhp/2]root         20      2  0     0     0   2 Feb16 ?        00:00:00 [watchdog/2]root         21      2  0     0     0   2 Feb16 ?        00:00:00 [migration/2]root         22      2  0     0     0   2 Feb16 ?        00:00:11 [ksoftirqd/2]root         24      2  0     0     0   2 Feb16 ?        00:00:00 [kworker/2:0H]

再来看下,所有内核线性的PPI=2, 也就是所有内核线性的父进程都是kthreadd进程。

UID         PID   PPID  C    SZ   RSS PSR STIME TTY          TIME CMDroot        362      1  0 21574  6136   2 Feb16 ?        00:00:03 /lib/systemd/systemd-journaldroot        375      1  0 11906  2760   3 Feb16 ?        00:00:01 /lib/systemd/systemd-udevdsystemd+    417      1  0 17807  2116   3 Feb16 ?        00:00:02 /lib/systemd/systemd-resolvedsystemd+    420      1  0 35997   788   3 Feb16 ?        00:00:00 /lib/systemd/systemd-timesyncdroot        487      1  0 43072  6060   0 Feb16 ?        00:00:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-triggersroot        489      1  0  8268  2036   2 Feb16 ?        00:00:00 /usr/sbin/cron -froot        490      1  0  1138   548   0 Feb16 ?        00:00:01 /usr/sbin/acpidroot        491      1  0 106816 3284   1 Feb16 ?        00:00:00 /usr/sbin/ModemManagerroot        506      1  0 27628  2132   2 Feb16 ?        00:00:01 /usr/sbin/irqbalance --foreground

所有用户态的进程的父进程PPID=1,也就是1号进程都是他们的父进程。

关于“linux中0号进程的含义是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网操作系统频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: linux中0号进程的含义是什么

本文链接: https://www.lsjlt.com/news/351785.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • linux中0号进程的含义是什么
    这篇文章主要介绍“linux中0号进程的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux中0号进程的含义是什么”文章能帮助大家解决问题。在linux中,0号进程是指idle进程,是...
    99+
    2023-07-05
  • php中“==”符号的含义是什么
    在php中,“==”符号是一个比较运算符,可以比较两个操作数是否相等,语法“操作数1 == 操作数2”。“==”运算符会比较、并测试左边的变量(表达式或常量)是否与右边的变量(表达式或常量)具有相同的值;它只比较变量的值,而不是数据类型。如...
    99+
    2023-05-14
    php 运算符 比较运算符
  • linux中stream的含义是什么
    这篇文章主要介绍“linux中stream的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux中stream的含义是什么”文章能帮助大家解决问题。 ...
    99+
    2023-03-19
    linux stream
  • linux中ll的含义是什么
    这篇文章主要讲解了“linux中ll的含义是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux中ll的含义是什么”吧!在linux中,“ll”是“ls -l”命令的别名,ls命令用...
    99+
    2023-06-29
  • Linux中点的含义是什么
    这篇文章主要介绍了Linux中点的含义是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Paul Brown 解释了 Linux shell 命令中那个不起眼的“点”的各种...
    99+
    2023-06-16
  • linux中samba的含义是什么
    这篇文章主要讲解了“linux中samba的含义是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“linux中samba的含义是什么”吧!在linux中,samba是一个基于SMB协议的开...
    99+
    2023-06-30
  • linux中tmp的含义是什么
    本篇内容主要讲解“linux中tmp的含义是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“linux中tmp的含义是什么”吧! ...
    99+
    2023-03-10
    linux tmp
  • linux shell中$$的含义是什么
    这篇文章主要介绍“linux shell中$的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux shell中$的含义是什么”文章能帮助大家解决问题。在linux中,shell是一个...
    99+
    2023-06-29
  • linux中load average的含义是什么
    在Linux中,load average(负载平均值)是指在一段时间内系统中正在运行或等待运行的进程的平均数。它通常指的是过去1分钟...
    99+
    2024-03-15
    linux
  • linux中分区的含义是什么
    本篇内容介绍了“linux中分区的含义是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!在linux中,分区就是把一片空间分割成多块,是指...
    99+
    2023-06-29
  • linux中命令的含义是什么
    今天小编给大家分享一下linux中命令的含义是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-03-19
    linux
  • linux中路径的含义是什么
    这篇文章主要介绍“linux中路径的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux中路径的含义是什么”文章能帮助大家解决问题。linux中路径是指包含整个文件名称及文件的位置,这...
    99+
    2023-07-05
  • linux i686的含义是什么
    本文小编为大家详细介绍“linux i686的含义是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“linux i686的含义是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识...
    99+
    2023-03-24
    linux
  • linux mv的含义是什么
    今天小编给大家分享一下linux mv的含义是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一...
    99+
    2023-04-19
    linux
  • linux .exe的含义是什么
    本篇内容介绍了“linux .exe的含义是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!linux .exe是指exe文件;在Linu...
    99+
    2023-07-05
  • linux ppc64的含义是什么
    今天小编给大家分享一下linux ppc64的含义是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来...
    99+
    2023-03-23
    linux
  • linux i386的含义是什么
    这篇文章主要介绍“linux i386的含义是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“linux i386的含义是什么”文章能帮助大家解决问题。 ...
    99+
    2023-04-14
    linux
  • Linux grub的含义是什么
    本文小编为大家详细介绍“Linux grub的含义是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“Linux grub的含义是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识...
    99+
    2023-04-19
    linux grub
  • linux dash的含义是什么
    本篇内容介绍了“linux dash的含义是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
    99+
    2023-04-20
    linux dash
  • linux server的含义是什么
    今天小编给大家分享一下linux server的含义是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起...
    99+
    2023-03-19
    linux
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作