zoukankan      html  css  js  c++  java
  • 20191317王鹏宇第五章学习笔记

    第五章:定时器及时钟服务

    知识点归纳总结

    本章讨论了定时器和定时器服务;介绍了硬件定时器的原理和基于Intel x86的PC中的硬件定时器;

    讲解了CPU操作和中断处理;描述了Linux中与定时器相关的系统调用、库函数和定时器服务命令;

    探讨了进程间隔定时器、定时器生成的信号,并通过示例演示了进程间隔定时器。编程项目的目的是要在一个多任务处理系统中实现定时器、定时器中断和间隔定时器。

    多任务处理系统作为一个Linux进程运行,该系统是Linux进程内并发任务的一个虚拟CPU, Linux进程的实时模式间隔定时器被设计为定期生成S1GALRM信号,充当虚拟CPU的定时器中断,虚拟CPU使用SIGALRM信号捕捉器作为定时器的中断处理程序。


    其中让我最有收获的几个部分如下:

    • CPU操作
    • 中断处理
    • 时钟服务函数
    • 间隔计时器
    • 编程项目样例代码

    时钟服务函数

    `gettimeofday()`使用gettimeofday()来查看当前时间,这个函数会计算从1970年1月1号00:00(UTC)到当前的时间跨度。 > 说明:在使用gettimeofday()函数时,第二个参数一般都为空,因为我们一般都只是为了获得当前时间,而不用获得timezone的数值

    其函数原型如下:

    #include <sys/time.h>
    // 调用成功返回0,失败返回-1
    int gettimeofday(struct timeval *tv, struct timezone *tz);
    
    struct timeval {
        time_t      tv_sec;     /* seconds */
        suseconds_t tv_usec;    /* microseconds */
    };
    

    示例代码:

    /************gettimeofday.c file**********/
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <time.h>
    
    struct timeval t;
    
    int main()
    {
        gettimeofday(&t,NULL);
        printf("sec=%ld usec=%d
    ",t.tv_sec,t.tv_usec);
        printf("%s",(char *)ctime(&t.tv_sec));
    }
    

    实践截图:

    settimeofday 设置当前时间戳,settimeofday()会把目前时间设成由tv 所指的结构信息,当地时区信息则设成tz 所指的结构。

    #include <time.h>
    
    int settimeofday(const struct timeval *tv , const struct timezone *tz);
    
    struct timeval {undefined
        time_t      tv_sec;     /* seconds */
        suseconds_t tv_usec;    /* microseconds */
    
    };
    

    示例函数:

    /***********settimeofday.c file*************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <time.h>
    
    struct timeval t;
    
    int main()
    {
        int r;
        t.tv_sec = 123456789;
        t.tv_usec = 0;
        /*if(!r)
        {
            printf("settimeofday() faild
    ");
            exit(1);
        }*/
        gettimeofday(&t,NULL);
        printf("sec=%ld usec=%ld
    ",t.tv_sec,t.tv_usec);
        printf("%s", ctime(&t.tv_sec));
        
    }
    

    实践截图:

    time系统调用

    time_t time(time_t *t)
    以秒为单位返回当前时间。如果参数t不是NULL,还会将时间存储在t指向的内存中。 time系统调用具有一定的局限性,只提供以秒为单位的分辨率,而不是以微秒为单位。

    #include <stdio.h>
    #include <time.h>
    
    time_t start, end;
    
    int main()
    {
        int i;
        start = time(NULL);
        printf("start = %ld
    ", start);
        for ( i = 0; i < 123456789; i++)
        {
            end = time(NULL);
        }
        printf("end = %ld time = %ld
    ",end ,end-start);
    }
    

    time 和 date 命令

    • date:打印或设置系统日期和时间。
    • time:报告进程在用户模式和系统模式下的执行时间和总时间。
    • hwclock:查询并设置硬件时钟(RTC),也可以通过BIOS来完成。

    间隔定时器
    定时器仅在进程以 用户模式执行时才减少计时。该定时器设置为完成最初100毫秒计时后开始计时:然后,它以1秒为周期运行。当定时器计时减少为0时,它会向进程发出一个SIGVTALRM ( 26 )信 号。如果进程未安装该信号的捕捉器,将会对该信号进行默认处理,即终止:在这种情况 下,进程将以信号数26终止。如果进程安装了信号捕捉器.Linux内核会让进程执行信号 捕捉器,以用户模式处理信号、在间隔时间开始之前,程序通过以下代码安装SIGVTALRM 信号的信号捕捉器;
    void timer_handler(int sig)
    signal(SIGALRMZ timer_handler)
    安装信号捕捉器后,程序启动定时器,然后在while(l)循环中执行-当在循环中执行时,每个硬件中断(例如来自硬件定时器的中断)都会导致CPU以及在CPU上执行的进程进入Linux内核来处理中断,当进程处于内核模式时,会检查待处理信号。如有待处理信号,它会试图先处理信号再返回用户模式。在这种情况下,SIGVTALRM信号将导致进程在用户模式下执行信号捕捉器,由于信号定时器程程序设计为每秒生成一个信号,进程将每秒执行一次timer_handler(),使打印消息像脉冲星一样每秒显示一次。
    信号捕捉函数timer_handler()可计算定时器的时间结束次数当计数达到规定值(例如8)时,它用定时器值0来取消setitimer()设置的间隔定时器。虽然定时器已经停止,但进程仍在无限while(l)循环中执行。 在这种情况下,从键盘按下"Ctrl+C”组合键,可以使进程以SIGINT(2)信号终止。

    #include <signal.h>
    #include <stdio.h>
    #include <sys/time.h>
    
    int count = 0;
    struct itimerval t;
    
    void timer_handler(int sig)
    {
        printf("timer_handler : signal = %d count = %d
    ", sig, ++count);
        if(count>=8)
        {
            printf("cancel timer
    ");
            t.it_value.tv_sec = 0;
            t.it_value.tv_usec = 0;
            setitimer(ITIMER_VIRTUAL, &t ,NULL);
        }
    }
    
    int main()
    {
        struct itimerval timer;
        signal(SIGVTALRM, timer_handler);
        timer.it_value.tv_sec = 0;
        timer.it_value.tv_usec = 10000;
    
        timer.it_interval.tv_sec = 1;
        timer.it_interval.tv_usec = 0;
        setitimer(ITIMER_VIRTUAL, &timer,NULL);
        printf("looping : enter Control-C to terminate
    ");
        while(1);
    }
    

    实践截图:

    编程项目示例

    ts.s file:
    #-----------ts. s file-----------+		 
    .global tswitch, scheduler, running 
    tswitch:
    SAVE:   pushal
            pushfl
            movl running, %ebx
            movl %esp , 4(%ebp)
    FIND:   call scheduler
    RESUME: movl running, %ebx
            movl 4(%ebx), %esp
            popfl
            popal
            ret
    
    

    t.c file:

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <string.h>
    #include <sys/time.h>
    
    #define NPROC	9
    #define SSIZE	1024
    // PROC status	
    #define FREE	0
    #define READY	1
    #define SLEEP	2
    #define BLOCK	3
    #define PAUSE	4
    #define ZOMBIE  5
    
    typedef struct	proc {  
        struct proc	*next;
        int ksp;	//
        int pid;	//
        int priority;	//
        int status;	//
        int event;	//
        int ppid;
        int exitStatus;
        int joinPid;	
        int time;	//
        int pause;	//
        int stack[SSIZE];	//
    }PROC;	
    
    PROC proc[NPROC];
    PROC *freeList, *readyQueue, *running;
    PROC *sleepList;
    PROC *pauseList;
    #include "queue.c"
    //#include "wait.c" 
    
    int menu()
    {
        printf("**********menu**********
    ");
        printf("* creat switch exit ps *
    ");
        printf("************************
    ");
    }
    
    int init()
    {
        int i, j;
        PROC *p;
        for (i=0; i<NPROC; i++)
        {
            p = &proc[i];
            p->pid = i;
            p->priority = 1;
            p->status = FREE; 
            p->event = 0; 
            p->next = p+1;
        }
        proc[NPROC-1].next = 0;
        freeList = &proc[0];	// all PROCs in freeList
        readyQueue = 0;
        sleepList = 0;
        pauseList = 0;
        // create P0 as initial running task 
        running = dequeue(&freeList);
        running->status = READY;
        running->priority = 0; // P0 has lowest priority 0 
        printList("freeList", freeList);
        printf("init complete: P0 running
    ");
    }
    
    int do_exit()
    {
        printf("task %d exit: ", running->pid); 
        running->status = FREE; 
        running->priority = 0;
        enqueue(&freeList, running);
        printList("freeList", freeList); 
        tswitch();
    }
    
    int do_ps()
    {
        printf("---------ps---------
    ");
        printList("readyQueue", readyQueue);
        printList("sleepList ", sleepList);
        printf ("-------------------
    "); 
    }
    
    int create(void (f)(), void *parm) // create a new task
    {
        int i;
        PROC *p = dequeue(&freeList);
        if (!p)
        {
            printf("create failed
    ");
            return -1;
        }
        p->ppid = running->pid;
        p->status = READY;
        p->priority = 1;
        for (i=1; i<12; i++)
            p->stack[SSIZE-i] = 0;
    
        p->stack[SSIZE-1] = (int)parm;
        p->stack[SSIZE-2] = (int)do_exit;
        p->stack[SSIZE-3] = (int)f;
        p->ksp = &p->stack[SSIZE-12];
        enqueue(&readyQueue, p);
        printf("%d created a new task %d
    ", running->pid, p->pid); 
        return p->pid;
    }
    
    int func(void *parm)
    {
        char line[64], cmd[16];
        printf("task %d start: parm = %d
    ", running->pid, parm); 
        while(1)
        {
            printf("task %d running
    ", running->pid);
            menu();
            printf("enter a command line:");
            fgets(line, 64, stdin);
            line[strlen(line)-1] = 0; // kill 
     at end of line 
            sscanf(line, "%s", cmd);
            if (strcmp(cmd, "create")==0)
                create((void *)func, 0);
            else if (strcmp(cmd, "switch")==0)
                tswitch();
            else if (strcmp(cmd, "exit")==0)
                do_exit();
            else if (strcmp(cmd, "ps")==0)
                do_ps();
        }
    }
    
    int main()
    {
        int i;
        printf("Welcome to the MT multitasking system
    "); 
        init();
        for (i=1; i<5; i++)	// create tasks
            create((void *)func, 0);
        printf("P0 switch to Pl
    ");
        while(1)
        {
            if (readyQueue) 
                tswitch();
        }
    }
    int scheduler()
    {
        if (running->status == READY)
        enqueue(&readyQueue, running);
        running = dequeue(&readyQueue);
        printf("next running = %d
    ", running->pid);
    
    }
    

    项目运行截图:

  • 相关阅读:
    C# 语音识别
    Android—监听器
    android-Activity
    Android小案例——简单图片浏览器
    针对Android 模拟器启动慢的问题
    emulator-arm.exe 已停止工作、 emulator-x86 已停止工作
    android模拟器启动没有拨号功能
    安装好android的adt以后重启eclipse,但是没有创建AVD的图标
    android环境搭建——工欲善其事,必先利其器 2
    SQL 中常见的系统存储过程
  • 原文地址:https://www.cnblogs.com/wpy-1049363419/p/15510374.html
Copyright © 2011-2022 走看看