Linux 定时器应用
实验目的
阅读 Linux 相关源代码,学习 Linux 系统中的时钟和定时器原理,即,ITIMER_REAL
实时计数,ITIMER_VIRTUAL 统计进程在用户模式执行的时间,ITIMER_PROF 统计进程
在用户模式和核心模式下的执行时间。
理解这些定时器的实现机制。
掌握操作定时器的命令,掌握定时器的使用。
实验内容
ITIMER_REAL 实时计数;ITIMER_VIRTUAL 统计进程在用户模式(进程本身执行)
执行的时间;ITIMER_PROF 统计进程在用户模式(进程本身执行)和核心模式(系统代表
进程执行)下的执行时间,与 ITIMER_VIRTUAL 比较,这个计时器记录的时间多了该进程
核心模式执行过程中消耗的时间。
针对一个计算 fibonacci 数的进程,设定三个定时器,获取该进程在用户模式的运行时
间,在核心模式的运行时间,以及总的运行时间。
实验提示
一、一个应用定时器的简单例子
我们首先来看一个关于 ITIMER_REAL 定时器的例子。在这个例子里面我们将会设置
一个 ITIMER_REAL 类型的定时器,它每过一秒都会发出一个信号,等到定时到达的时候
(即定时器时间值减到 0),程序将统计已经经过的时间。下面是具体的代码:
/*我们在使用 signal 和时钟相关的结构体之前,需要包含这两个头文件*/
#include <signal.h>
#include <sys/time.h>
 
/*声明信号处理函数,信号相关内容将在第八章同步机制中讲述,读者在这里只要明白这个函数是
在进程收到信号的时候调用就可以了*/
static void sig_handler(int signo);
 
long lastsec,countsec;    /*这两个变量分别用来保存上一秒的时间和总共花去的时间*/
 
int main(void)
{
                struct itimerval v;              /*定时器结构体,结构体内容请参阅第三节中的介绍*/
                long nowsec,nowusec;      /*当前时间的秒数和微秒数*/                 /*注册 SIGUSR1 和 SIGALARM 信号的处理函数为 sig_handler*/
                if(signal(SIGUSR1,sig_handler)==SIG_ERR)
                {
                                printf("Unable to create handler for SIGUSR1\n");
                                exit(0);
                }
                if(signal(SIGALRM,sig_handler)==SIG_ERR)
                {
                                printf("Unable to create handler for SIGALRM\n");
                                exit(0);
                }
                /*初始化定时器初值和当前值*/
                v.it_interval.tv_sec=9;
                v.it_interval.tv_usec=999999;
                v.it_value.tv_sec=9;
                v.it_value.tv_usec=999999;
                 
/*调用 setitimer 设置定时器,并将其挂到定时器链表上,这个函数的三个参数的含义分
别是设置 ITIMER_REAL 类型的定时器,要设置的值存放在变量 v 中,该定时器设置前
的值在设置后保存的地址,如果是这个参数为 NULL,那么就放弃保存设置前的值*/
                setitimer(ITIMER_REAL,&v,NULL);
       
                lastsec=v.it_value.tv_sec;
                countsec=0;
 
/*该循环首先调用 getitimer 读取定时器当前值,再与原来的秒数比较,当发现已经过了
一秒后产生一个 SIGUSR1 信号,程序就会进入上面注册过的信号处理函数*/
                while(1)
                {
                                getitimer(ITIMER_REAL,&v);
                                nowsec=v.it_value.tv_sec;
                                nowusec=v.it_value.tv_usec;
                                if(nowsec==lastsec-1)
{
                                    /*每过一秒,产生一个 SIGUSR1 信号*/
                                                raise(SIGUSR1);     
                                                lastsec=nowsec;
                                                countsec++;            /*记录总的秒数*/
                                }
                }       
}
 
/*信号处理函数*/
static void sig_handler(int signo)
{
                switch(signo)
                {
                                /*接收到的信号是 SIGUSR1,打印 One second passed*/
                                case SIGUSR1:                                                 printf("One second passed\n");
                                                break;
                                /*定时器定时到达*/
                                case SIGALRM:
                                {
                                                printf("Timer has been zero,elapsed %d seconds\n",countsec);
                                                lastsec=countsec;
                                                countsec=0;
                                                break;
                                }
                }
}
 
上面的程序比较简单,主要是给大家看一下定时器的设置和读取的方法。下面我们将上
面的程序稍作修改,利用本章第一节介绍过的与进程相关的三种定时器来统计一个进程的用
户模式时间、核心模式时间、CPU 时间和总的进程执行时间。
二、统计关于进程的时间
我们在第一节介绍过和 Linux 进程相关的定时器有三种。ITIMER_REAL 实时计数;
ITIMER_VIRTUAL 统计进程在用户模式(进程本身执行)执行的时间;ITIMER_PROF 统
计进程在用户模式(进程本身执行)和核心模式(系统代表进程执行)下的执行时间,与
ITIMER_VIRTUAL 比较,这个计时器记录的时间多了该进程核心模式执行过程中消耗的时
间。通过在一个进程中设定这三个定时器,我们就可以了解到一个进程在用户模式、核心模
式以及总的运行时间。下面的这个程序除了定义了三个定时器和信号处理过程以外,其它的
地方和上面的程序完全相同。
 
#include <signal.h>
#include <sys/time.h>
 
static void sig_handler(int signo);
long countsec,lastsec,nowsec;
 
int main(void)
{
                struct itimerval v;
 
      /*注册信号处理函数*/
                if(signal(SIGUSR1,sig_handler)==SIG_ERR)
                {
                                printf("Unable to create handler for SIGUSR1\n");
                                exit(0);
                }
                if(signal(SIGALRM,sig_handler)==SIG_ERR)
                {
                printf("Unable to create handler for SIGALRM\n");
                                exit(0);
                }  
                v.it_interval.tv_sec=10;
                v.it_interval.tv_usec=0;
                v.it_value.tv_sec=10;
                v.it_value.tv_usec=0;
 
/*调用 setitimer 设置定时器,并将其挂到定时器链表上,这个函数的三个参数的含义分
别是设置何种类型的定时器;要设置的值存放在变量 v 中;该定时器设置前的值在设置
后保存的地址,如果是这个参数为 NULL,那么就放弃保存设置前的值*/
                setitimer(ITIMER_REAL,&v,NULL);
                setitimer(ITIMER_VIRTUAL,&v,NULL);
                setitimer(ITIMER_PROF,&v,NULL);
                countsec=0;
                lastsec=v.it_value.tv_sec;
                while(1)
                {
                                getitimer(ITIMER_REAL,&v);
                                nowsec=v.it_value.tv_sec;
                                if(nowsec==lastsec-1)
                                {
                                                if(nowsec<9)
                                                {
                                                                /*同上面一样,我们每隔一秒发送一个 SIGUSR1 信号*/
                                                                raise(SIGUSR1);
                                                                countsec++;
                                                }
                                                lastsec=nowsec;
                                }
}       
}
 
static void sig_handler(int signo)
{
                struct itimerval u,v;
                long t1,t2;
 
                switch(signo)
                {
                                case SIGUSR1:
                                        /*显示三个定时器的当前值*/
                                                getitimer(ITIMER_REAL,&v);
                                                printf("real time=%.ld secs %ld
usecs\n",9-v.it_value.tv_sec,999999-v.it_value.tv_usec);
                                                getitimer(ITIMER_PROF,&u);
                                                printf("cpu time=%ld secs %ld
usecs\n",9-u.it_value.tv_sec,999999-u.it_value.tv_usec);
                                                getitimer(ITIMER_VIRTUAL,&v);
                                                printf("user time=%ld secs %ld
usecs\n",9-v.it_value.tv_sec,999999-v.it_value.tv_usec);                                                 /*当前 prof timer 已经走过的微秒数*/
                                                t1=(9-u.it_value.tv_sec)*1000000+(1000000-u.it_value.tv_usec);
                                                /*当前 virtual timer 已经走过的微秒数*/
                                                t2=(9-v.it_value.tv_sec)*1000000+(1000000-v.it_value.tv_usec);
                                                /*计算并显示 kernel time*/
                                                printf("kernel time=%ld secs %ld
usecs\n\n",(t1-t2)/1000000,(t1-t2)%1000000);
                                                break;
                case SIGALRM:
                                printf("Real Timer has been zero,elapsed %d seconds\n",countsec);
                                exit(0);
                                break;
                }
}
 
从上面的程序可以看出来,ITIMER_REAL 定时器运行的时间就是总运行时间,
ITIMER_PROF 定时器的运行时间就是 CPU 花在该进程上的所有时间。ITIMER_VIRTUAL
定时器运行的时间是进程在用户模式的运行时间。ITIMER_PROF 定时器的运行时间减去
ITIMER_VIRTUAL 定时器的运行时间就是进程在核心模式的运行时间。
三、更进一步的进程时间统计
上面的程序只在很短的时间内统计了进程在各种状态的执行时间。但是进程并没有真正
的负载作业,和现实中的进程差距比较大。下面我们要继续修改上面的程序,让这个进程做
点“事情”,然后我们再来看看在和实际情况比较相近的状态下定时器统计到的进程在各个
状态下的时间。在这个程序里面我们将创建两个子进程,加上父进程总共三个进程,这三个
进程分别调用 fibonacci()计算 fibonacci 数。在计算之前我们初始化定时器,完成之后,我们
将读取定时器,然后来统计进程相关的各种时间。
 
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
 
long unsigned int fibonacci(unsigned int n);    /*计算 fibonacci 数的函数*/
static void par_sig(int signo);    /*父进程的信号处理函数*/
static void c1_sig(int signo);      /*子进程 1 的信号处理函数*/
static void c2_sig(int signo);      /*子进程 2 的信号处理函数*/
 
/*用于分别记录父,子 1,子 2 进程 real time 过的总秒数*/
static long p_realt_secs=0,c1_realt_secs=0,c2_realt_secs=0;     
/*用于分别记录父,子 1,子 2 进程 virtual time 过的总秒数*/
static long p_virtt_secs=0, c1_virtt_secs=0,c2_virtt_secs=0;
/*用于分别记录父,子 1,子 2 进程 proft time 过的总秒数*/
static long p_proft_secs=0,c1_proft_secs=0,c2_proft_secs=0;     
/*用于分别取出父,子 1,子 2 进程的 real timer 的值*/
static struct itimerval p_realt,c1_realt,c2_realt;     
/*用于分别取出父,子 1,子 2 进程的 virtual timer 的值*/ static struct itimerval p_virtt,c1_virtt,c2_virtt;     
/*用于分别取出父,子 1,子 2 进程的 proft timer 的值*/
static struct itimerval p_proft,c1_proft,c2_proft;     
 
int main()
{
                long unsigned fib=0;
                int pid1,pid2;
                unsigned int fibarg=39;
                int status;
                struct itimerval v;
                long moresec,moremsec,t1,t2;
 
                pid1=fork();
                if(pid1==0)
                {
                                /*设置子进程 1 的信号处理函数和定时器初值*/
                                signal(SIGALRM,c1_sig);
                                signal(SIGVTALRM,c1_sig);
                                signal(SIGPROF,c1_sig);
                                v.it_interval.tv_sec=10;
                                v.it_interval.tv_usec=0;
                                v.it_value.tv_sec=10;
                                v.it_value.tv_usec=0;
                                setitimer(ITIMER_REAL,&v,NULL);
                                setitimer(ITIMER_VIRTUAL,&v,NULL);
                                setitimer(ITIMER_PROF,&v,NULL);
                                fib=fibonacci(fibarg);    /*计算 fibonacci 数*/
                                /*取出子进程 1 的定时器值*/
                                getitimer(ITIMER_PROF,&c1_proft);     
                                getitimer(ITIMER_REAL,&c1_realt);
                                getitimer(ITIMER_VIRTUAL,&c1_virtt);
/*通过定时器的当前值和各信号发出的次数计算子进程 1 总共用的 real time,cpu
time,user time 和 kernel time。moresec 和 moremsec 指根据定时器的当前值计算
出的自上次信号发出时过去的 real time,cpu time,user time 和 kernel time。计算
kernel time 时,moresec 和 moremsec 为 kernel time 的实际秒数+毫秒数*/
                                moresec=9-c1_realt.it_value.tv_sec;
moremsec= (1000000-c1_realt.it_value.tv_usec)/1000;
                                printf("Child 1 fib=%ld , real time=%ld sec,%ld
msec\n",fib,c1_realt_secs+moresec,moremsec);
                                moresec=9-c1_proft.it_value.tv_sec;
                                moremsec=(1000000-c1_proft.it_value.tv_usec)/1000;
                                printf("Child 1 fib=%ld , cpu time=%ld sec,%ld
msec\n",fib,c1_proft_secs+moresec,moremsec);
                                moresec=9-c1_virtt.it_value.tv_sec;
moremsec=(1000000-c1_virtt.it_value.tv_usec)/1000;
                                printf("Child 1 fib=%ld , user time=%ld sec,%ld
msec\n",fib,c1_virtt_secs+moresec,moremsec);                                         
t1=(9-c1_proft.it_value.tv_sec)*1000+(1000000-c1_proft.it_value.tv_usec)/1000+c1_proft_secs*10000;
t2=(9-c1_virtt.it_value.tv_sec)*1000+(1000000-c1_virtt.it_value.tv_usec)/1000+c1_v
i rtt_secs*10000;
                                moresec=(t1-t2)/1000;moremsec=(t1-t2)%1000;
                                printf("Child 1 fib=%ld , kernel time=%ld sec,%ld msec\n",fib,moresec,moremsec);
                                fflush(stdout);
                                exit(0);             
                }
                else
                {
                                pid2=fork();
                                if(pid2==0)
                                {
                                                /*设置子进程 2 的信号处理函数和定时器初值*/
                                                signal(SIGALRM,c2_sig);
                                                signal(SIGVTALRM,c2_sig);
                                                signal(SIGPROF,c2_sig);
                                                v.it_interval.tv_sec=10;
                                                v.it_interval.tv_usec=0;
                                                v.it_value.tv_sec=10;
                                                v.it_value.tv_usec=0;
                                                setitimer(ITIMER_REAL,&v,NULL);
                                                setitimer(ITIMER_VIRTUAL,&v,NULL);
                                                setitimer(ITIMER_PROF,&v,NULL);
                                                fib=fibonacci(fibarg);
                                                /*取出子进程 2 的定时器值*/
                                                getitimer(ITIMER_PROF,&c2_proft);
                                                getitimer(ITIMER_REAL,&c2_realt);
                                                getitimer(ITIMER_VIRTUAL,&c2_virtt);
/*通过定时器的当前值和各信号发出的次数计算子进程 2 总共用的 real
time,cpu time,user time 和 kernel time。moresec 和 moremsec 指根据定时
器的当前值计算出的自上次信号发出时过去的 real time,cpu time,user
time 和 kernel time。计算 kernel time 时,moresec 和 moremsec 为 kernel
time 的实际秒数+毫秒数*/
                                                moresec=9-c2_realt.it_value.tv_sec;
                                                moremsec=(1000000-c2_realt.it_value.tv_usec)/1000;
                                        printf("Child 2 fib=%ld , real time=%ld sec,%ld   
msec\n",fib,c2_realt_secs+moresec,moremsec);
                                                moresec=9-c2_proft.it_value.tv_sec;
                                moremsec=(1000000-c2_proft.it_value.tv_usec)/1000;
                                              printf("Child 2 fib=%ld , cpu time=%ld sec,%ld   
msec\n",fib,c2_proft_secs+moresec,moremsec);
                                                moresec=9-c2_virtt.it_value.tv_sec;
moremsec=(1000000-c2_virtt.it_value.tv_usec)/1000;
                                                printf("Child 2 fib=%ld , user time=%ld sec,%ld
                                msec\n",fib,c2_virtt_secs+moresec,moremsec);
                 
t1=(9-c2_proft.it_value.tv_sec)*1000+(1000000-c2_proft.it_value.tv_usec)/
1000+c2_proft_secs*10000;                  
t2=(9-c2_virtt.it_value.tv_sec)*1000+(1000000-c2_virtt.it_value.tv_usec)/1
000+c2_virtt_secs*10000;
                                                moresec=(t1-t2)/1000;
moremsec=(t1-t2)%1000;
                                                printf("Child 2 fib=%ld , kernel time=%ld sec,%ld
msec\n",fib,moresec,moremsec);
                                                fflush(stdout);
                                                exit(0);
                                }   
                                else
                                {
                                                /*设置父进程的信号处理函数和定时器初值*/
                                                signal(SIGALRM,par_sig);
                                                signal(SIGVTALRM,par_sig);
                                                signal(SIGPROF,par_sig);
                                                v.it_interval.tv_sec=10;
                                                v.it_interval.tv_usec=0;
                                                v.it_value.tv_sec=10;
                                                v.it_value.tv_usec=0;
                                                setitimer(ITIMER_REAL,&v,NULL);
                                                setitimer(ITIMER_VIRTUAL,&v,NULL);
                                                setitimer(ITIMER_PROF,&v,NULL);
                                                fib=fibonacci(fibarg);
                                                /*取出父进程的定时器值*/
                                                getitimer(ITIMER_PROF,&p_proft);
                                                getitimer(ITIMER_REAL,&p_realt);
                                                getitimer(ITIMER_VIRTUAL,&p_virtt);
/*通过定时器的当前值和各信号发出的次数计算子进程 1 总共用的
real time,cpu time,user time 和 kernel time。moresec 和 moremsec 指根据
定时器的当前值计算出的自上次信号发出时过去的 real time,cpu
time,user time 和 kernel time。计算 kernel time 时,moresec 和 moremsec
为 kernel time 的实际秒数+毫秒数*/
                                                moresec=9-p_realt.it_value.tv_sec;
moremsec=(1000000-p_realt.it_value.tv_usec)/1000;
                                                printf("Parent fib=%ld , real time=%ld sec,%ld
msec\n",fib,p_realt_secs+moresec,moremsec);
                                                moresec=9-p_proft.it_value.tv_sec;
moremsec=(1000000-p_proft.it_value.tv_usec)/1000;
                                                printf("Parent fib=%ld , cpu time=%ld sec,%ld
msec\n",fib,p_proft_secs+moresec,moremsec);
                                                moresec=9-p_virtt.it_value.tv_sec;
moremsec=(1000000-p_virtt.it_value.tv_usec)/1000;
                                                printf("Parent fib=%ld , user time=%ld sec,%ld
msec\n",fib,p_virtt_secs+moresec,moremsec);
                   
t1=(9-p_proft.it_value.tv_sec)*1000+(1000000-p_proft.it_value.tv_usec)/1
000+p_proft_secs*10000;
                 7t2=(9-p_virtt.it_value.tv_sec)*1000+(1000000-p_virtt.it_value.tv_usec)/10
00+p_virtt_secs*10000;
                                                moresec=(t1-t2)/1000;
moremsec=(t1-t2)%1000;
                                                printf("Parent fib=%ld , kernel time=%ld sec,%ld
msec\n",fib,moresec,moremsec);
                                                fflush(stdout);
                                                waitpid(0,&status,0);
                                                waitpid(0,&status,0);
                                                exit(0);
                                }
                                printf("this line should never be printed\n");
                }
}
 
long unsigned fibonacci(unsigned int n)
{
                if(n==0)
                                return 0;
                else if(n==1||n==2)
                                return 1;
                else
                                return (fibonacci(n-1)+fibonacci(n-2));
}
 
/*父进程信号处理函数;每个 timer 过 10 秒减为 0,激活处理函数一次,相应的计数器加 10*/
static void par_sig(int signo)
{
 
                switch(signo)
                {
                                case SIGALRM:
                                                p_realt_secs+=10;
                                                break;
                                case SIGVTALRM:
                                                p_virtt_secs+=10;
                                                break;
                                case SIGPROF:
                                                p_proft_secs+=10;
                                                break;
                }
}
 
/*子进程 1 的信号处理函数,功能与父进程的信号处理函数相同*/
static void c1_sig(int signo)
{
 
                switch(signo)
                {                                 case SIGALRM:
                                                c1_realt_secs+=10;
                                                break;
                                case SIGVTALRM:
                                                c1_virtt_secs+=10;
                                                break;
                                case SIGPROF:
                                                c1_proft_secs+=10;
                                                break;
                }
}
 
/*子进程 2 的信号处理函数,功能与父进程的信号处理函数相同*/
static void c2_sig(int signo)
{
 
                switch(signo)
                {
                                case SIGALRM:
                                                c2_realt_secs+=10;
                                                break;
                                case SIGVTALRM:
                                                c2_virtt_secs+=10;
                                                break;
                                case SIGPROF:
                                                c2_proft_secs+=10;
                                                break;
                }
}
 
在上面的程序中,我们为三个进程使用了三个不同的信号处理函数,这是因为每个进程
需要处理的数据不同。如果在 Linux 中运行这个程序,那么我们就可以看到下面的结果:
Child 1 fib=63245986 , real time=20 sec,250 msec
Child 1 fib=63245986 , cpu time=6 sec,840 msec
Child 1 fib=63245986 , user time=6 sec,800 msec
Child 1 fib=63245986 , kernel time=0 sec,40 msec
Child 2 fib=63245986 , real time=20 sec,380 msec
Child 2 fib=63245986 , cpu time=6 sec,850 msec
Child 2 fib=63245986 , user time=6 sec,840 msec
Child 2 fib=63245986 , kernel time=0 sec,10 msec
Parent fib=63245986 , real time=20 sec,290 msec
Parent fib=63245986 , cpu time=6 sec,870 msec
Parent fib=63245986 , user time=6 sec,820 msec
Parent fib=63245986 , kernel time=0 sec,50 msec
大家可以试着运行一下,看看结果是不是如上所示。当然每个人得到的具体时间可能都
不同,这个要看具体机器的运算速度。

Linux 定时器应用【转】的更多相关文章

  1. linux定时器用法

    linux定时器  原文出自http://www.cnblogs.com/processakai/archive/2012/04/11/2442294.html 今天看书看到了关于alarm的一些用法 ...

  2. linux定时器crontab

    linux定时器crontab用法: 1.基本格式 : * * * * * command 分 时 日 月 周 命令 第1列表示分钟1-59 每分钟用*或者 */1表示 第2列表示小时1-23(0表示 ...

  3. 4412 Linux定时器

    一.Linux定时器基础知识 1.1 定时器的使用范围 延后执行某个操作,定时查询某个状态:前提是对时间要求不高的地方 1.2 内核时间概念 Hz:(系统时钟通过CONFIG_HZ来设置,范围是100 ...

  4. linux定时器(crontab)实例

    linux实验示例----实现每2分钟将“/etc”下面的文件打包存储到“/usr/lobal”目录下 ·Step1:编辑当前用户的crontab并保存终端输入:>crontab -u root ...

  5. Linux定时器相关源码分析

    Linux的定时器使用时间轮算法.数据结构不难理解,核心数据结构与散列表及其相似,甚至可以说,就是散列表.事实上,理解其散列表的本质,有助于对相关操作的理解. 数据结构 这里先列出一些宏,稍后解释: ...

  6. Smart210学习记录-----linux定时器

    1.内核定时器: Linux 内核所提供的用于操作定时器的数据结构和函数如下: (1) timer_list 在 Linux 内核中,timer_list 结构体的一个实例对应一个定时器 1 stru ...

  7. linux 定时器编程实例(完善中).....

    最近在写linux 下的定时器编程实验,测试发现 usleep函数在 x86 架构下的定时还是比较准确的,在arm9下 就不太准了. 今天用linux 下的setitimer()函数进行了定时 器的测 ...

  8. linux定时器HZ和Jiffies

    1.linux HZ Linux核心几个重要跟时间有关的名词或变数,以下将介绍HZ.tick与jiffies. HZ Linux核心每隔固定周期会发出timer interrupt (IRQ 0),H ...

  9. linux定时器

    我们常常有设置系统在某一时间执行相应动作的需求,比如设置电脑什么时候自动锁屏,什么时候自动关机,设置应用程序什么时候自动运行,什么时候自动退出.这些与时间相关的功能,都需要依靠操作系统中的定时器来实现 ...

随机推荐

  1. (第三周)使用visual studio 2015进行单元测试

    Microsoft visual studio是目前最流行的windows平台应用程序的集成开发环境.最新版本为 Visual Studio 2015 .Visual Studio 2015 包含许多 ...

  2. [2017BUAA软工]提问回顾

    原博客链接 原问题1:有没有系统的方法来提高一开始的文档的设计后的质量呢 在之前的OO课程上,我已经深刻领会到了设计的重要性,而且在这次的团队开发中,我也是负责从需求分析到代码设计的转换,所以对设计这 ...

  3. mysql 清空数据

    清空数据有2 个命令 -- 清空全部数据,不写日志,不可恢复,速度极快 truncate table 表名; -- 清空全部数据,写日志,数据可恢复,速度慢 delete from 表名 业务需求:清 ...

  4. shareSDK.js web版的使用

    自定义将要分享的内容 <!--MOB SHARE BEGIN--> <div class="-mob-share-open">分享</div> ...

  5. postman 学习网址

    postman使用详解: http://gold.xitu.io/entry/57597a62a341310061337885 https://www.getpostman.com/docs/writ ...

  6. Ubuntu17安装maven3.5.2

    1.下载maven 源码文件.tar.gz 2.解压源文件sudo tar -zxvf .tar.gz文件 3.配置/etc/profile文件 export MAVEN_HOME=/app/java ...

  7. poj3368 Frequent values(线段树)

    Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In ad ...

  8. 【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理

    题目描述 给出 $n$ 个点和 $n-1$ 种颜色,每种颜色有若干条边.求这张图多少棵每种颜色的边都出现过的生成树,答案对 $10^9+7$ 取模. 输入 第一行包含一个正整数 N(N<=17) ...

  9. Spring中ClassPathXmlApplication与FileSystemXmlApplicationContext的区别以及ClassPathXmlApplicationContext 的具体路径

    一.ClassPathXmlApplicationContext 的具体路径 String s[] = System.getProperty("java.class.path"). ...

  10. luogu3778/bzoj4898 商旅 (floyd+分数规划+spfa)

    首先floyd求出来每两点间的最短距离,然后再求出来从某点买再到某点卖的最大收益 问题就变成了找到一个和的比值最大的环 所以做分数规划,二分出来那个答案r,把边权变成w[i]-r*l[i],再做spf ...