KVM虚拟化技术-实战与原理解析

第23章 定时器与休眠

1.间隔定时器setitimer和alarm

两个重要的结构体:定时器参数struct itimerval和表示时间struct timerval。


struct itimerval {
    struct timeval it_interval;     /* Interval for periodic timer */
    struct timeval it_value;        /* Current value (time until next expiration) */  为0则是一次性定时器。
};

struct timeval {
    time_t      tv_sec;             /* Seconds */
    suseconds_t tv_usec;            /* Microseconds (long int) */
};

setitimer和alarm原型:


#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
    Returns 0 on success, or –1 on error
int getitimer(int which, struct itimerval *curr_value);
    Returns 0 on success, or –1 on error

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
    Always succeeds, returning number of seconds remaining on any previously set timer, or 0 if no timer previously was set

setitimer可以指定三种不同类型定时器:ITIMER_REAL(SIGALARM)、ITIMER_VIRTUAL(SIGVTALRM)、ITIMER_PROF(SIGPROF)。

  • 进程只能拥有三种定时器的一种。
  • alarm()和setitimer()针对统一进程共享同一实时定时器。
  • 三种定时器的参考时间不同,ITIMER_REAL(真实时间)、ITIMER_VIRTUAL(进程虚拟时间,用户CPU时间)、ITIMER_PROF(进程的用户和内核时间总和)。
  • 如果这些信号不设置处理函数,则默认会终止进程。

2.定时器的调度及精度

  • 系统可能会在定时器到期的瞬间之后才去调度其所属进程,这取决于当前负载和对进程的调度。
  • setitimer()定时器虽然可能延迟一定时间,但是后续的定时器仍然按照固定间隔。比如2秒定时器,2.3超时,下一个应该在4.3秒超时。
  • 虽然setitimer精度达到微妙,但是受制于软件时钟频率。比如jiffy为4ms,间隔为19100微妙,实际间隔是20ms。
  • 高分辨率定时器需要内核CONFIG_HIGH_RES_TIMERS。

3.为阻塞操作设置超时

4.休眠一段时间

低分辨率休眠sleep()


#include <unistd.h>
unsigned int sleep(unsigned int seconds);
    如果休眠正常结束,返回0。如果被中断,返回剩余秒数。可能由于系统负载调度原因,会在sleep到时候才对进程重新加以调度。

高分辨率休眠nanosleep()


#define _POSIX_C_SOURCE 199309
#include <time.h>
int nanosleep(const struct timespec *request, struct timespec *remain);
    Returns 0 on successfully completed sleep, or –1 on error or interrupted sleep

request指定了休眠持续时间,理论上精度可以达到纳秒级,但受制于软件时钟间隔。如果间隔并非间隔值,者向上取整。

nanosleep()不基于信号实现,但是可以通过型号处理函数来中断,如SIGINT(Ctrl-C)。
再被中断之后,剩余时间可以通过remain中获取。将remain赋给request,则可以继续睡眠剩余时间。

5.POSIX时钟

POSIX时钟API必须以-lrt选项进行编译,从而与librt函数库链接,主要系统调用包括获取当前值的clock_gettime()、返回时钟分辨率的clock_getres()、以及更新时钟的clock_settime()。

要测定特定进程或线程所消耗的CPU时间,可以借助clock_getcpuclockid/pthread_getcpuclockid来获取时钟ID,接着再以此返回ID去调用clock_gettime(),从而获得进程或线程耗费的CPU时间。pid为0是,clock_getcpuclockid()返回调用进程的CPU时间时钟ID。


#define _POSIX_C_SOURCE 199309
#include <time.h>
int clock_gettime(clockid_t clockid, struct timespec *tp);
int clock_getres(clockid_t clockid, struct timespec *res);
    Both return 0 on success, or –1 on error

int clock_settime(clockid_t clockid, const struct timespec *tp);
    Returns 0 on success, or –1 on error

int clock_getcpuclockid(pid_t pid, clockid_t *clockid);
    Returns 0 on success, or a positive error number on error

int pthread_getcpuclockid(pthread_t thread, clockid_t *clockid);
    Returns 0 on success, or a positive error number on error

int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain);
    Returns 0 on successfully completed sleep or a positive error number on error or interrupted sleep

Linux特有的clock_nanosleep()系统调用也可以暂停调用进程,知道经理一段指定时间,亦或是收到信号才恢复运行。


int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain);
Returns 0 on successfully completed sleep,or a positive error number on error or interrupted sleep

默认情况下(flags为0),request指定休眠间隔是相对时间;如果flags设定TIMER_ABSTIME,request则表示clockid时钟所测量的绝对时间。

相对时间问题:如果只是先获取当前时间,计算与目标时间差距,再以相对时间进行休眠,进程可能执行到一半就奔抢占了,结果实际休眠时间回避预期要久。如果被信号处理函数中断并使用循环重启休眠,则“嗜睡”问题尤其明显。如果信号频率很高,则按相对时间休眠的进程则会有较大时间误差。

避免嗜睡问题:先调用clock_gettime()获取时间,加上期望休眠的时间量,再以TIMER_ABSTIME标识调用clock_nanosleep()函数。指定TIMER_ABSTIME,不再使用参数remain。如果信号中断clock_nanosleep()调用,再次调用该函数来重启休眠时,request参数不变。clock_nanosleep()和nanosleep()另一区别在可以选择不同的时钟来测量休眠间隔时间。

6.POSIX间隔式定时器


#define _POSIX_C_SOURCE 199309
#include <signal.h>
#include <time.h>
int timer_create(clockid_t clockid, struct sigevent *evp,timer_t *timerid);
    Returns 0 on success, or –1 on error

int timer_settime(timer_t timerid, int flags,const struct itimerspec *value, struct itimerspec *old_value);
    Returns 0 on success, or –1 on error

int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
    Returns 0 on success, or –1 on error

int timer_delete(timer_t timerid);
    Returns 0 on success, or –1 on error

int timer_getoverrun(timer_t timerid);
    Returns timer overrun count on success, or –1 on error

CLOCK_REALTIME时钟是一种系统级时钟,用于度量真实时间。

CLOCK_MONOTONIC系统启动后就不会发生改变,适用于那些无法容忍系统时钟发生跳跃性变化的应用。Linux上这种时钟对事件的测量食欲系统启动。

CLOCK_PROCESS_CPUTIME_ID时钟测量调用进程所消耗的用户和系统CPU时间。

CLOCK_THREAD_CPUTIME_ID时钟用于测量进程中单条线程的用户和系统CPU时间。

7.文件描述符定时器:timerfd API

Linux特有的timerfd API,可以从文件描述符中读取其所创建定时器的到期通知,也可以用使用select()、poll()、epoll()监控。

#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
clockid可以设置为CLOCK_REALTIME或者CLOCK_MONOTONIC。
相当于open创建一个句柄,可以使用close()关闭响应文件描述符。

int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);

timerfd_settime()启动了定时器,可以通过read()来读取定时器到期信息。read缓冲区必须容纳uint64_t类型,读取返回值是已发生的到期次数。

执行./demo_timerfd 1:1 100,使用Ctrl-Z将其变成挂起到背景执行,fg拉倒前台,Ctrl-C终止执行。可以看出在背景执行期间有10此到期。


./demo_timerfd 1:1 100
1.000: expirations read: 1; total=1
2.000: expirations read: 1; total=2
3.000: expirations read: 1; total=3
4.000: expirations read: 1; total=4
^Z
[2]+  Stopped                 ./demo_timerfd 1:1 100
fg
./demo_timerfd 1:1 100
14.734: expirations read: 10; total=14
15.000: expirations read: 1; total=15
16.000: expirations read: 1; total=16
17.000: expirations read: 1; total=17
18.000: expirations read: 1; total=18
^Z
[2]+  Stopped                 ./demo_timerfd 1:1 100

8.总结

setitimer()和alarm()设定定时器,以便于在经历指定的一段实际时间后收到信号通知。

sleep()和nano_sleep()指定程序暂停执行一段特定间隔的实际时间。

timerfd_create()、timerfd_settime()、timerfd_gettime()提供一组创建定时器的接口,允许从文件秒速附中读取特定定时器通知。可以使用read()、select()、poll()、epoll()、close()来操作这些描述符。

时间: 2024-08-25 10:32:13

KVM虚拟化技术-实战与原理解析的相关文章

[转] KVM虚拟化技术生态环境介绍

KVM虚拟化技术生态环境介绍 http://xanpeng.github.io/wiki/virt/kvm-virtulization-echosystem-intro.html kvm和qemu/qemu-kvm的关系 qemu vs. qemu-kvm: 从qemu 1.3开始,kvm userspace code就维护在qemu mainline中(git clone https://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git, ref) qe

KVM虚拟化技术

KVM虚拟化技术 Qemu-kvm kvm Qemu-kvm创建和管理虚拟机 1.KVM简介 KVM(名称来自英语:Kernel-basedVirtual Machine的缩写,即基于内核的虚拟机),是一种用于Linux内核中的虚拟化基础设施,可以将Linux内核转化为一个hypervisor.KVM在2007年2月被导入Linux 2.6.20核心中,以可加载核心模块的方式被移植到FreeBSD及illumos上. KVM在具备Intel VT或AMD-V功能的x86平台上运行.它也被移植到S

深入浅出KVM虚拟化技术

深入浅出KVM虚拟化技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 其实虚拟化技术已经不是一个新技术了,上个世纪六十年代IBM公司已经在使用,只不过后来随着PC机的出现,虚拟化为最初的应用目的已经可用武之地了,但是随着X86系统的增多以及PC机性能的提升以及现在业务模式的需要,所以使得虚拟化技术再一次蓬勃发展起来.在上个世纪的1974年有2位很著名的教授Popek和Glodberg在一篇论文中定义了经典虚拟化应该至少满足三个需求: 1>.等价执行(除了资源可用性以及时间上

Linux下kvm虚拟化技术的安装与使用

Linux下kvm虚拟化技术的安装与使用 云时代的到来,虚拟化的广泛应用.让我们重新的科技进行了定义.而当下知名的虚拟化产品有 vmware vsphere ,Hyper-v,xen,kvm.vmware的虚拟化所占的市场有目共睹,Hyper-V是windows平台下的虚拟化,而Xen就属于一个半虚拟化产品.kvm就是我们今天所介绍的对象. (kvm是kernel virtual module的简写)kvm是红帽公司5.4版本后所推出的最新虚拟化技术产品.它和vpc,virtual  box都属

KVM虚拟化技术(一)

KVM虚拟化技术(一) =============================================================================== 概述: =============================================================================== 虚拟化技术基础 1.介绍 ★cpu虚拟化: ☉模拟:emulation ☉虚拟:virtulization 完全虚拟化(full-virtuliza

kvm虚拟化技术应用实战

本文根据上课笔记整理,大家都知道云计算的基础就是虚拟化,而开源的虚拟化基本以kvm技术为主导,因此kvm技术已成为运维工程师必备的技术,也是云时代必不可少的技术 在介绍kvm之前 我们先来了解一下vnc这个软件,后面安装kvm需要vnc来支持 1.vnc的安装及使用 # yum -y install tigervnc-server 首次启动 # vncserver :1 会提示输入两次密码 然后编辑/root/.vnc/xstartup,将最后一行twm替换为gnome-session或者sta

KVM虚拟化技术(二)KVM介绍

KVM:Kernel Virtual Machine KVM是基于虚拟化扩展的x86硬件,是Linux完全原生的全虚拟化解决方案.部分半虚拟化支持,主要是通过半虚拟网络驱动程序的形式用于Linux和Windows客户机系统的. KVM被设计为是一个内核模块,支持广泛的客户机操作系统:在KVM架构中,虚拟机实现为常规的Linux进程.这使KVM能够享受Linux内核的所有功能. KVM模块是KVM虚拟机的核心部分.其主要功能是初始化CPU硬件,打开虚拟化模式,然后将虚拟机客户机运行在虚拟机模式下,

KVM虚拟化技术(一)虚拟化简介

一 .虚拟化 虚拟化是指计算机元件在虚拟的基础上而不是真实的基础上运行.虚拟化技术可以扩大硬件的容量,简化软件的重新配置过程.CPU的虚拟化技术可以单CPU模 拟多CPU并行,允许一个平台同时运行多个操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率. 虚拟化的类型: 全虚拟化 半虚拟化(涉及修改guestos内核,因此仅支持开源kernel的系统) 硬件辅助虚拟化(主板上开启虚拟化支持) 几种虚拟化软件简介 KVM 完全虚拟化 架构:寄居架构(linux

KVM虚拟化技术之使用Qemu-kvm创建和管理虚拟机

一.KVM简介 KVM(名称来自英语:Kernel-basedVirtual Machine的缩写,即基于内核的虚拟机),是一种用于Linux内核中的虚拟化基础设施,可以将Linux内核转化为一个hypervisor.KVM在2007年2月被导入Linux 2.6.20核心中,以可加载核心模块的方式被移植到FreeBSD及illumos上. KVM在具备Intel VT或AMD-V功能的x86平台上运行.它也被移植到S/390,PowerPC与IA-64平台上.在Linux内核3.9版中,加入A