linux内核时钟节拍tick_linux tick-程序员宅基地

技术标签: linux  开源软件  

本文所有代码分析均基于linux-5.4.18
1.  时钟节拍tick
        时钟节拍tick是一个逻辑概念,它本身和时间没有关系,是linux系统周期性时钟的一次中断,仅表示系统的一次嘀嗒。在SMP系统中,linux内核会为每个cpu core创建一个tick device,它的实现基于clock event device ,struct tick_device结构体两个成员,其中一个就是clock event device。
        tick为周期性时钟的一次中断,linux内核支持两种时钟,一种为传统时钟,精度较低,另外一种为高精度时钟,精度为ns级。早期linux只支持传统时钟,在2.6.16以后加入了高精度时钟的支持。目前两种时钟都在使用,在内核启动时,tick首先默认使用传统时钟,然后会切换到高精度模式。
        linux内核中的tick周期为tick_period = NSEC_PER_SEC / HZ,即tick = 1s/HZ,表示系统里每个tick间隔为1/HZ秒,HZ这个参数,由内核的编译配置项CONFIG_HZ指定,取值可以为100、250、300、1000。
        tick的计数用jiffies变量表示,jiffies变量是一个计数器,用来记录系统启动以来产生的节拍总数。tick每发生一次,它便加“1”。
        这里多说一句,linux的时钟tick对preempt rt linux实时性影响不大,缩短tick间隔,并不会对微秒级的实时性有所提高。
1.1 start_kernel阶段的一些时钟相关初始化(可另做研究)
init/mian.c
        start_kernel()
                --> init_IRQ();
                --> tick_init()
                        --> tick_broadcast_init();
                        --> tick_nohz_init();
                --> init_timers();
                --> hrtimers_init();
                        --> hrtimers_prepare_cpu(smp_processor_id());
                        --> open_softirq(HRTIMER_SOFTIRQ, hrtimer_run_softirq);
                --> softirq_init();
                --> time_init();
                --> sched_clock_init();
1.2 时钟节拍tick实现
        arm架构设备上,linux内核中tick的实现入口在arm_arch_timer.c中
        inux内核启动时,首先会申请arch_timer中断,中断处理函数中直接执行clock event device的event_handler。然后会在cpu up阶段,为每个cpu core注册一个clock event设备arch_timer_evt,注册时会创建一个tick device(tick_cpu_device)。当tick发生,触发arch_timer中断,在arch_timer中断处理中在,执行clock event 设备arch_timer_evt的event_handler。
        linux内核启动初期,tick使用传统时钟实现,这时在arch_timer_evt的event_handler中,尝试切换到高精度模式和执行其他工作:jiffies计数加1、更新墙上时间、scheduler_tick()等。
        tick的整个实现过程如下:
  1. 在arch_timer驱动中申请arch_timer中断,并注册中断处理函数。在中断处理函数中,完成clock event设备arch_timer_evt的event_handler(tick_handle_periodic/hrtimer_interrupt)的执行
  2. 在arch_timer中设置cpu up过程中CPUHP_AP_ARM_ARCH_TIMER_STARTING阶段的回调函数arch_timer_starting_cpu,在cpu up对应阶段调用。
  3. 在每个cpu core的cpu up过程的对应阶段,执行arch_timer_starting_cpu,在其中会进行新的clock event设备arch_timer_evt的配置和注册,注册arch_timer_evt的时,还有以下几个工作:
    • 完成arch_timer_evt设备所在tick device的创建,当前mode为TICKDEV_MODE_PERIODIC。
    • 设置arch_timer_evt的event_handler为tick周期处理函数tick_handle_periodic(),此时内核使用传统时钟,所以tick_handle_periodic()为传统时钟下arch_timer_evt的event_handler
  4. 当arch_timer中断触发后,执行clock event 设备arch_timer_evt的event_handler,即tick_handler_periodic()。主要工作有:jiffies计数加“1”、更新墙上时间、尝试切换到高精度模式以及scheduler_tick()的执行。
  5. 其中尝试切换到高精度模式以及scheduler_tick()的执行,通过调用update_process_times()完成。
  6. update_process_times()首先会判断是否已经切到了高精度模式,如果是直接返回,然后执行scheduler_tick()。如果没有切换到高精度模式,尝试切换到高精度模式后,在执行scheduler_tick()。
  7. 如果没有切换到高精度模式前,判断当前满足切换条件,调用hrtimer_switch_to_hres,尝试切换到高精度模式。如果不满足切换条件,则在__hrtimer_run_queues中通过while循环查询是否有到期定时器,如果有,通过__run_hrtimer执行其处理函数。hrtimer_switch_to_hres()切换到高精度模式的工作主要如下:
    • 通过tick_init_highres() 间接调用tick_switch_to_oneshot(hrtimer_interrupt),设置高精度模式下,clock event设备arch_timer_evt的event_handler,从之前的tick_handle_periodic改为hrtimer_interrupt。切换到高精度模式后,arch_timer中断到来后,便不再执行tick_handle_periodic(),而是改为hrtimer_interrupt()。
    • 调用tick_setup_sched_timer() 完成高精度定时器sched_timer的初始化和启动。周期tick_period = NSEC_PER_SEC / HZ,超时处理函数为tick_sched_timer。
  8. 在切换到高精度模式后,每次tick到来,即arch_timer中断到来后,执行clock event设备arch_timer_evt的event_handler,此时为hrtimer_interrupt()。在hrtimer_interrupt()判断并执行sched_timer的超时处理函数tick_sched_timer()。
  9. tick_sched_timer()主要工作如下:
    • tick_do_update_jiffies64()更新jiffies计数及墙上时间
    • 通过tick_sched_handle()的调用执行update_process_times(),详见步骤6,由于此时在高精度模式下,所以直接执行scheduler_tick();
    • hrtimer_forward(timer, now, tick_period);重新推迟sched_timer定时器,时间间隔为tick_period;
    • 返回HRTIMER_RESTART;
  10. sched_timer超时后,arch_timer中断触发,返回步骤8。
1.2.1 arch timer设备
        linux内核时钟节拍tick,通过clock event devices实现。linux内核启动时,在每个cpu code的cpu up的CPUHP_AP_ARM_ARCH_TIMER_STARTING阶段,为当前cpu core注册clock event device(arch_timer_evt)并创建tick device(tick_cpu_device)。
        linux内核时钟节拍tick,其实就是arch_timer的一次中断,在内核启动初期,tick使用传统时钟,然后会尝试切换到高精度时钟
        arch_timer设备的一些工作:
  1. 为每个cpu core申请arch_timer中断,并为其注册中断处理函数,在中断处理函数中会执行clock event设备的event_handler,比如时钟tick所在的clock event设备arch_timer_evt的event_handler
  2. 设置cpu up过程中,CPUHP_AP_ARM_ARCH_TIMER_STARTING阶段的回调函数arch_timer_starting_cpu(),在cpu up的对应阶段调用。clock event设备arch_timer_evt的注册以及tick设备tick_cpu_device的创建都在回调函数arch_timer_starting_cpu()完成。
  3. 使用clocksource_register_hz()注册一个新的时钟源clocksource_counter,启动高精度定时器sched_clock_timer等等。
drivers/clocksource/arm_arch_timer.c
    /* arm时钟源驱动的入口函数,根据设备树或者acpi分别采用不同的入口 */
    arch_timer_of_init() / arch_timer_acpi_init()
        --> arch_timer_register()
            /*
             * 根据arch_timer_uses_ppi模式,为每个cpu core申请arch_timer中断,
             * 中断处理中的操作:
             * 读取arch timer控制寄存器ARCH_TIMER_REG_CTRL的值
             * 如果发现STAT位被置位,清楚此位
             * 执行对应clock event设备的event_handler()
             */
            --> request_percpu_irq(ppi, arch_timer_handler_phys,
                         "arch_timer", arch_timer_evt);
            --> arch_timer_cpu_pm_init()
            /*
             * 设置CPU状态机中CPUHP_AP_ARM_ARCH_TIMER_STARTING状态的回调函数
             * 在cpu up对应阶段进行调用。
             * 回调函数中完成clock event设备(arch_timer_evt)的注册
             * 和tick device(tick_cpu_device)的创建。
             */
            --> cpuhp_setup_state(CPUHP_AP_ARM_ARCH_TIMER_STARTING,
                        "clockevents/arm/arch_timer:starting",
                        arch_timer_starting_cpu, arch_timer_dying_cpu);
        --> arch_timer_common_init()
            --> arch_timer_banner(arch_timers_present);
            --> arch_counter_register(arch_timers_present);
                /* 注册新的时钟源clocksource_counter */
                --> clocksource_register_hz(&clocksource_counter, arch_timer_rate);
                --> timecounter_init(&arch_timer_kvm_info.timecounter, &cyclecounter, start_count);
                /* 主要用来启动sched_clock_timer,用来更新sched clock,以供sched_clock()方法使用 */
                --> sched_clock_register(arch_timer_read_counter, 56, arch_timer_rate);
            --> arch_timer_arch_init()
        arch_timer的中断处理函数arch_timer_handler_phys()中直接调用timer_handler()完成以下工作:
  • 首先读取ARCH_TIMER_REG_CTRL寄存器的值
  • 如果ARCH_TIMER_CTRL_IT_STAT被置位,清楚标志位,
  • 最后执行对应clock event设备的event_handler
drivers/clocksource/arm_arch_timer.c
timer_handler(ARCH_TIMER_PHYS_ACCESS, evt)
{
    /* 读取寄存器ARCH_TIMER_REG_CTRL值 */
    ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL, evt);
    if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
        ctrl |= ARCH_TIMER_CTRL_IT_MASK;
        arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, evt);
        /* 执行对应clock event设备的event_handler() */
        evt->event_handler(evt);
        return IRQ_HANDLED;
    }
    return IRQ_NONE;
}
        以上是arm架构上arch_timer设备的初始化和简单逻辑,本文主要介绍时钟节拍tick,其相关实现在cpu up过程CPUHP_AP_ARM_ARCH_TIMER_STARTING阶段的回调函数中arch_timer_starting_cpu()实现。
1.2.2  clock event设备的注册和tick device的创建
        在linux内核启动过程中,会对CPU核进行唤醒动作,这个过程每个CPU核会经过几个不同的阶段,其中包括CPUHP_AP_ARM_ARCH_TIMER_STARTING(包含在CPUHP_AP_OFFLIEN至CPUHP_AP_ONLINE阶段中,参考CPUHOTPLUG),为CPU核上的arch_timer启动阶段,这个工作通过执行状态对应的回调函数arch_timer_starting_cpu()完成。
        这个过程中会注册一个clock event设备arch_timer_evt,然后通过tick_setup_device()完成tick设备tick_cpu_device的创建。tick设备结构体struct tick_device中只有两个成员变量,其中一个便为clock event device。
struct tick_device {
    struct clock_event_device *evtdev;
    enum tick_device_mode mode;
};
        配置注册clock event设备以及tick设备的创建流程如下:
drivers/clocksource/arm_arch_timer.c
    arch_timer_starting_cpu()
        --> __arch_timer_setup(ARCH_TIMER_TYPE_CP15, clk);
               /* 
                * 配置并注册clock event设备arch_timer_evt
                * 然后set up the tick device
                */
            --> clockevents_config_and_register();
        --> enable_percpu_irq()
        --> arch_counter_set_user_access();
        clockevents_config_and_register()中配置并注册clock event 设备,然后执行tick_check_new_device()-->tick_setup_device()进行tick device创建
kernel/time/clockevents.c
    clockevents_config_and_register()
        --> clockevents_config()
            /* register the clock event device */
        --> clockevents_register_device(struct clock_event_device *dev)
            --> list_add(&dev->list, &clockevent_devices);
                /* 主要执行tick_setup_device()创建tick device  */
            --> tick_check_new_device()
            --> clockevents_notify_released()
        创建tick设备,同时设置当前传统时钟下clock event设备的event_handler
kernel/time/tick_common.c
    tick_check_new_device()
            /* Setup the tick device */
        --> tick_setup_device()
                /* 设置其周期tick_perio;*/
            --> tick_period = NSEC_PER_SEC / HZ;
                /* 设置tick device模式为TICKDEV_MODE_PERIODIC */
            --> td->mode = TICKDEV_MODE_PERIODIC;
                /*
                 * 根据tick设备mode,调用tick_setup_periodic创建tick device
                 * 设置clock event设备的event_handler和operating state
                 */
            --> tick_setup_periodic()
                    /* 设置clock event设备arch_timer_evt的event_handler */
                --> tick_set_periodic_handler(dev, broadcast);  
                    /*
                     * linux内核启动初期,tick仍然使用传统时钟实现,此时
                     * clock event设备的event_handler为tick_handle_periodic()
                     * 后期会尝试切换到到高精度模式,然后修改clock event设备的event_handler
                     * 高精度模式下clock event设备的event_handler为hrtimer_interrupt()
                     */
                    --> dev->event_handler = tick_handle_periodic;
                    /* 设置clock event设备的operating state为periodic
                --> clockevents_switch_state(dev, CLOCK_EVT_STATE_PERIODIC)
1.2.3 传统时钟下tick处理
        每次tick便会产生一次arch_timer中断, 此时arch_timer中断处理中执行的clock event设备arch_timer_evt的event_handler。linux-2.6.16后虽然支持了高精度时钟,但是内核启动初期,tick仍采用传统时钟实现,传统时钟下,clock event设备arch_timer_evt的event_handler为tick_handle_periodic()。
        tick_handle_periodic()的代码逻辑如下:
kernel/time/tick_common.c
    /* Event handler for periodic ticks */
    tick_handle_periodic()
            /* 周期性时钟具体处理函数 */
        --> tick_periodic()
                /* Keep track of the next tick event */
            --> tick_next_period = ktime_add(tick_next_period, tick_period);
                /* jiffies计数加“1” */
            --> do_timer(1);
                /* 更新墙上时间 */
            --> update_wall_time();
                /* 主要处理函数,切换高精度时钟、scheduler_tick()执行 */
            --> update_process_times()
        update_process_times()的主要工作如下:
  1. update_process_times()首先会判断是否已经切到了高精度模式,如果是直接执行步骤3操作;
  2. 内核启动前期,必然没有切到高精度模式。这个时候每个时钟tick便会检查是否可以切换,如果可以,则使用hrtimer_switch_to_hres()中尝试切换到高精度模式;否则在__hrtimer_run_queues中执行对应的定时器超时处理。
  3. 执行scheduler_tick()。
kernel/time/timer.c
    update_process_times()
        --> run_local_timers()
                /*
                * 判断是否切换到了高精度模式,如果切换到了高精度模式,不做任何处理
                * 如果没有切到高精度模式,判断是否具备切换到高精度模式条件
                * 如果具备条件,执行hrtimer_switch_to_hres()中尝试切换到高精度模式
                * 否则执行__hrtimer_run_queues()进行定时器超时查询处理
                */
            --> hrtimer_run_queues();
        --> scheduler_tick();    /* 检查是否需要进行任务切换 */
1.2.4 切换到高精度模式:调度时钟(sched_timer)初始化及启动
        切换到高精度模式主要完成以下工作:
  1. 将clock event设备的event_handler改为hrtimer_interrupt()。高精度模式下,时钟到期后发生arch_timer中断,执行hrtimer_interrupt()完成到时时钟的处理,即执行超时处理函数。
  2. 将tick device的mode和clock eventdevice的state设置为oneshot。
  3. 初始化并启动高精度定时器sched_timer,周期为tick_period,超时处理函数为tick_sched_timer
linux内核切换到高精度模式后,tick通过高精度定时器sched_timer实现。
kernel/time/hrtimer.c
    hrtimer_run_queues(void)
            /* 如果已经是高精度模式,直接return */
        --> if (__hrtimer_hres_active(cpu_base))    return;
                /*
                 * 这里其实有个判断,如果当前满足条件,
                 * 执行hrtimer_switch_to_hres()尝试切换到高精度模式
                 */
            --> hrtimer_switch_to_hres()
                    /* 切换到高精度模式 */
                --> tick_init_highres()
                        /*
                         * 将clock event设备的event_handler改为hrtimer_interrupt;
                         * 将tick device的mode和clock eventdevice的state设置为oneshot
                         */
                    --> tick_switch_to_oneshot(hrtimer_interrupt);
                            /* 设置tick device mode为oneshot */
                        --> td->mode = TICKDEV_MODE_ONESHOT;
                            /*
                             * 设置高精度模式下clock event设备的event_handler
                             * 从之前的tick_handle_periodic切换为hrtimer_interrupt
                             */
                        --> dev->event_handler =hrtimer_interrupt;
                            /* 设置clock event设备的state为oneshot */
                        --> clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT);
                    /* 初始化并启动sched_timer */
                --> tick_setup_sched_timer()
                    --> hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
                        /* sched_timer超时处理函数为tick_sched_timer */
                    --> ts->sched_timer.function = tick_sched_timer; 
                    --> hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update());
                    --> hrtimer_forward(&ts->sched_timer, now, tick_period);
                    --> hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED_HARD);
                    --> tick_nohz_activate(ts, NOHZ_MODE_HIGHRES);
                /*
                 * 当前不满足切换高精度模式条件,
                 * 执行__hrtimer_run_queues()进行定时器超时查询处理
                 */
            --> __hrtimer_run_queues()
1.2.5 高精度模式下,tick处理:sched_timer超时处理
        当linux内核切换到高精度模式后,时钟节拍tick通过sched_timer高精度定时器实现,当定时器sched_timer超时后触发arch_timer中断,arch_timer中断处理中执行clock event设备的event_handler,此时为hrtimer_interrupt(),hrtimer_interrupt()完成到时定时器的处理,即执行超时处理函数tick_sched_timer()。
kernel/time/tick-sched.c
    tick_sched_timer()
        /* 增加jiffies计数、更新墙上时间 */
        --> tick_sched_do_timer(ts, now); 
        --> tick_sched_handle(ts, regs);
            /*
             * 此方法上面已经介绍过了,不同的是:这边检查到已经切换到高精度模式后,
             * 不在进行其他操作,直接执行scheduler_tick(),后面有简单逻辑介绍。
             */
            --> update_process_times(user_mode(regs));
        /* 重新推迟定时器,时间为tick_period,即下一个tick */
        --> hrtimer_forward(timer, now, tick_period);
        --> return HRTIMER_RESTART;
kernel/time/time.c
    update_process_times()
        --> run_local_timers();
            /* 因为已经切换到高精度模式,所以这里不做任何操作,直接return了 */
            --> hrtimer_run_queues() 
                { 
                    if (__hrtimer_hres_active(cpu_base))  return;
                } 
        /* 检查是否需要进行任务切换 */
        --> scheduler_tick();
1.2.6 scheduler_tick
        linux内核在每个tick进行任务切换检查,检查标志TIF_NEED_RESCHED是否被设置,如被设置,则进行任务切换,详细参考linux任务调度。
kernel/sched/core.c
    scheduler_tick() { curr->sched_class->task_tick(rq, curr, 0); }
        /* 根据当前任务所属调度类执行对应task_tick方法 */
        --> task_tick_fair() / task_tick_rt() / task_tick_dl()
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/kkqier/article/details/130879375

智能推荐

18个顶级人工智能平台-程序员宅基地

文章浏览阅读1w次,点赞2次,收藏27次。来源:机器人小妹  很多时候企业拥有重复,乏味且困难的工作流程,这些流程往往会减慢生产速度并增加运营成本。为了降低生产成本,企业别无选择,只能自动化某些功能以降低生产成本。  通过数字化..._人工智能平台

electron热加载_electron-reloader-程序员宅基地

文章浏览阅读2.2k次。热加载能够在每次保存修改的代码后自动刷新 electron 应用界面,而不必每次去手动操作重新运行,这极大的提升了开发效率。安装 electron 热加载插件热加载虽然很方便,但是不是每个 electron 项目必须的,所以想要舒服的开发 electron 就只能给 electron 项目单独的安装热加载插件[electron-reloader]:// 在项目的根目录下安装 electron-reloader,国内建议使用 cnpm 代替 npmnpm install electron-relo._electron-reloader

android 11.0 去掉recovery模式UI页面的选项_android recovery 删除 部分菜单-程序员宅基地

文章浏览阅读942次。在11.0 进行定制化开发,会根据需要去掉recovery模式的一些选项 就是在device.cpp去掉一些选项就可以了。_android recovery 删除 部分菜单

mnn linux编译_mnn 编译linux-程序员宅基地

文章浏览阅读3.7k次。https://www.yuque.com/mnn/cn/cvrt_linux_mac基础依赖这些依赖是无关编译选项的基础编译依赖• cmake(3.10 以上)• protobuf (3.0 以上)• 指protobuf库以及protobuf编译器。版本号使用 protoc --version 打印出来。• 在某些Linux发行版上这两个包是分开发布的,需要手动安装• Ubuntu需要分别安装 libprotobuf-dev 以及 protobuf-compiler 两个包•..._mnn 编译linux

利用CSS3制作淡入淡出动画效果_css3入场效果淡入淡出-程序员宅基地

文章浏览阅读1.8k次。CSS3新增动画属性“@-webkit-keyframes”,从字面就可以看出其含义——关键帧,这与Flash中的含义一致。利用CSS3制作动画效果其原理与Flash一样,我们需要定义关键帧处的状态效果,由CSS3来驱动产生动画效果。下面讲解一下如何利用CSS3制作淡入淡出的动画效果。具体实例可参考刚进入本站时的淡入效果。1. 定义动画,名称为fadeIn@-webkit-keyf_css3入场效果淡入淡出

计算机软件又必须包括什么,计算机系统应包括硬件和软件两个子系统,硬件和软件又必须依次分别包括______?...-程序员宅基地

文章浏览阅读2.8k次。计算机系统应包括硬件和软件两个子系统,硬件和软件又必须依次分别包括中央处理器和系统软件。按人的要求接收和存储信息,自动进行数据处理和计算,并输出结果信息的机器系统。计算机是脑力的延伸和扩充,是近代科学的重大成就之一。计算机系统由硬件(子)系统和软件(子)系统组成。前者是借助电、磁、光、机械等原理构成的各种物理部件的有机组合,是系统赖以工作的实体。后者是各种程序和文件,用于指挥全系统按指定的要求进行..._计算机系统包括硬件系统和软件系统 软件又必须包括

随便推点

进程调度(一)——FIFO算法_进程调度fifo算法代码-程序员宅基地

文章浏览阅读7.9k次,点赞3次,收藏22次。一 定义这是最早出现的置换算法。该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。该算法实现简单,只需把一个进程已调入内存的页面,按先后次序链接成一个队列,并设置一个指针,称为替换指针,使它总是指向最老的页面。但该算法与进程实际运行的规律不相适应,因为在进程中,有些页面经常被访问,比如,含有全局变量、常用函数、例程等的页面,FIFO 算法并不能保证这些页面不被淘汰。这里,我_进程调度fifo算法代码

mysql rownum写法_mysql应用之类似oracle rownum写法-程序员宅基地

文章浏览阅读133次。rownum是oracle才有的写法,rownum在oracle中可以用于取第一条数据,或者批量写数据时限定批量写的数量等mysql取第一条数据写法SELECT * FROM t order by id LIMIT 1;oracle取第一条数据写法SELECT * FROM t where rownum =1 order by id;ok,上面是mysql和oracle取第一条数据的写法对比,不过..._mysql 替换@rownum的写法

eclipse安装教程_ecjelm-程序员宅基地

文章浏览阅读790次,点赞3次,收藏4次。官网下载下载链接:http://www.eclipse.org/downloads/点击Download下载完成后双击运行我选择第2个,看自己需要(我选择企业级应用,如果只是单纯学习java选第一个就行)进入下一步后选择jre和安装路径修改jvm/jre的时候也可以选择本地的(点后面的文件夹进去),但是我们没有11版本的,所以还是用他的吧选择接受安装中安装过程中如果有其他界面弹出就点accept就行..._ecjelm

Linux常用网络命令_ifconfig 删除vlan-程序员宅基地

文章浏览阅读245次。原文链接:https://linux.cn/article-7801-1.htmlifconfigping <IP地址>:发送ICMP echo消息到某个主机traceroute <IP地址>:用于跟踪IP包的路由路由:netstat -r: 打印路由表route add :添加静态路由路径routed:控制动态路由的BSD守护程序。运行RIP路由协议gat..._ifconfig 删除vlan

redux_redux redis-程序员宅基地

文章浏览阅读224次。reduxredux里要求把数据都放在公共的存储区域叫store里面,组件中尽量少放数据,假如绿色的组件要给很多灰色的组件传值,绿色的组件只需要改变store里面对应的数据就行了,接着灰色的组件会自动感知到store里的数据发生了改变,store只要有变化,灰色的组件就会自动从store里重新取数据,这样绿色组件的数据就很方便的传到其它灰色组件里了。redux就是把公用的数据放在公共的区域去存..._redux redis

linux 解压zip大文件(解决乱码问题)_linux 7za解压中文乱码-程序员宅基地

文章浏览阅读2.2k次,点赞3次,收藏6次。unzip版本不支持4G以上的压缩包所以要使用p7zip:Linux一个高压缩率软件wget http://sourceforge.net/projects/p7zip/files/p7zip/9.20.1/p7zip_9.20.1_src_all.tar.bz2tar jxvf p7zip_9.20.1_src_all.tar.bz2cd p7zip_9.20.1make && make install 如果安装失败,看一下报错是不是因为没有下载gcc 和 gcc ++(p7_linux 7za解压中文乱码