1. 函数介绍
getitimer 是一个 Linux 系统调用,专门用于查询当前进程的间隔计时器(interval timers)的当前状态。它允许程序了解指定类型计时器的剩余时间(距离下次超时还有多久)和重载时间(超时后会自动重启的周期)。
你可以把它想象成查看你设置的闹钟或定时器上还剩多少时间。
2. 函数原型
#include <sys/time.h> // 必需
int getitimer(int which, struct itimerval *curr_value);
3. 功能
- 查询状态: 获取由 
which参数指定的计时器类型的当前设置。 - 填充结构体: 将获取到的计时器状态信息填充到调用者提供的 
struct itimerval结构体指针curr_value所指向的内存中。 
4. 参数
int which: 指定要查询的计时器类型。与setitimer相同,主要有以下三种:ITIMER_REAL: 实时计时器。时钟源是系统实时时间,超时发送SIGALRM。ITIMER_VIRTUAL: 虚拟计时器。时钟源是进程在用户态的 CPU 时间,超时发送SIGVTALRM。ITIMER_PROF: 性能计时器。时钟源是进程在用户态和内核态的总 CPU 时间,超时发送SIGPROF。
struct itimerval *curr_value: 这是一个指向struct itimerval结构体的指针。getitimer调用成功后,会将查询到的计时器当前状态信息存储到这个结构体中。
5. struct itimerval 结构体
这个结构体在 setitimer 和 getitimer 中都使用,用于表示计时器的时间设置:
struct itimerval {
    struct timeval it_interval; // 重载时间 (Interval)
    struct timeval it_value;    // 当前值/剩余时间 (Value)
};
其中 struct timeval 定义了秒和微秒:
struct timeval {
    time_t      tv_sec;         // 秒
    suseconds_t tv_usec;        // 微秒 (0 - 999,999)
};
- 通过 
getitimer返回的curr_value:curr_value->it_value: 表示该计时器当前还剩多少时间就会超时。如果计时器未启动或已超时,这个值通常是 0。curr_value->it_interval: 表示该计时器被设置的重载时间(周期)。这个值是在调用setitimer时设置的,getitimer只是将其读取出来。
 
6. 返回值
- 成功时: 返回 0。同时,
curr_value指向的结构体被成功填充。 - 失败时: 返回 -1,并设置全局变量 
errno来指示具体的错误原因(例如EINVALwhich参数无效)。 
7. 相似函数,或关联函数
setitimer: 用于设置间隔计时器。getitimer与setitimer: 通常成对出现,用于查询和设置计时器。alarm/setitimer:alarm(seconds)大致等价于setitimer(ITIMER_REAL, ...)。timer_gettime: POSIX 定时器 API 中用于获取定时器时间的函数,功能更强大。clock_gettime: 用于获取各种系统时钟的当前时间。
8. 示例代码
示例 1:监控 ITIMER_REAL 的倒计时
这个例子演示了如何在启动一个 ITIMER_REAL 计时器后,使用 getitimer 在循环中监控其剩余时间。
#include <sys/time.h> // getitimer, setitimer
#include <signal.h>   // signal
#include <unistd.h>   // pause
#include <stdio.h>    // printf, perror
#include <stdlib.h>   // exit
#include <string.h>   // memset
volatile sig_atomic_t alarm_fired = 0;
void alarm_handler(int sig) {
    write(STDERR_FILENO, "Timer expired! SIGALRM received.\n", 32);
    alarm_fired = 1;
}
int main() {
    struct itimerval timer, current_timer;
    int seconds_to_wait = 5;
    if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
        perror("signal SIGALRM");
        exit(EXIT_FAILURE);
    }
    // 1. 设置 ITIMER_REAL 计时器
    memset(&timer, 0, sizeof(timer)); // 清零结构体是个好习惯
    timer.it_value.tv_sec = seconds_to_wait; // 5 秒后超时
    timer.it_interval.tv_sec = 0;            // 一次性,不重复
    printf("Setting ITIMER_REAL to expire in %d seconds.\n", seconds_to_wait);
    if (setitimer(ITIMER_REAL, &timer, NULL) == -1) {
        perror("setitimer");
        exit(EXIT_FAILURE);
    }
    printf("Monitoring timer countdown:\n");
    // 2. 循环监控计时器剩余时间
    while (!alarm_fired) {
        if (getitimer(ITIMER_REAL, ¤t_timer) == -1) {
            perror("getitimer");
            // 即使 getitimer 失败,也继续循环或退出
            break;
        }
        // 打印剩余时间
        printf("  Time remaining: %ld.%06ld seconds\n",
               (long)current_timer.it_value.tv_sec,
               (long)current_timer.it_value.tv_usec);
        // 简单延时 0.5 秒再检查 (可以使用 nanosleep 实现更精确的延时)
        usleep(500000); // 500,000 微秒 = 0.5 秒
    }
    if (alarm_fired) {
        printf("Timer has fired. Program exiting.\n");
    } else {
        printf("Loop exited before timer fired.\n");
    }
    return 0;
}
代码解释:
- 设置 
SIGALRM信号处理函数。 - 使用 
setitimer启动一个 5 秒后超时的一次性ITIMER_REAL计时器。 - 进入一个 
while循环,循环条件是alarm_fired标志为假。 - 在循环内部:
- 调用 
getitimer(ITIMER_REAL, ¤t_timer)获取计时器的当前状态。 - 检查返回值,处理可能的错误。
 - 打印 
current_timer.it_value中的剩余秒数和微秒数。 - 调用 
usleep(500000)延时 0.5 秒,然后继续下一次循环。 
 - 调用 
 - 当 
SIGALRM信号到达,alarm_handler被调用,设置alarm_fired为真,主循环退出。 
示例 2:检查周期性计时器的状态
这个例子演示了如何查询一个周期性计时器的剩余时间和重载时间。
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdatomic.h>
#include <string.h>
volatile atomic_int prof_count = 0;
void prof_handler(int sig) {
    atomic_fetch_add(&prof_count, 1);
    // 简单打印,实际信号处理应更谨慎
    write(STDERR_FILENO, "SIGPROF\n", 8);
}
int main() {
    struct itimerval timer, status;
    const int period_sec = 2;
    const int num_intervals = 3;
    if (signal(SIGPROF, prof_handler) == SIG_ERR) {
        perror("signal SIGPROF");
        exit(EXIT_FAILURE);
    }
    // 1. 设置 ITIMER_PROF 周期性计时器
    memset(&timer, 0, sizeof(timer));
    timer.it_value.tv_sec = period_sec;     // 第一次 2 秒后超时
    timer.it_interval.tv_sec = period_sec;  // 之后每 2 秒超时一次
    printf("Setting periodic ITIMER_PROF timer (every %d seconds).\n", period_sec);
    if (setitimer(ITIMER_PROF, &timer, NULL) == -1) {
        perror("setitimer ITIMER_PROF");
        exit(EXIT_FAILURE);
    }
    printf("Checking timer status immediately after setting:\n");
    if (getitimer(ITIMER_PROF, &status) == -1) {
        perror("getitimer ITIMER_PROF");
        exit(EXIT_FAILURE);
    }
    printf("  Current value (remaining time): %ld.%06ld seconds\n",
           (long)status.it_value.tv_sec, (long)status.it_value.tv_usec);
    printf("  Interval (reload time): %ld.%06ld seconds\n",
           (long)status.it_interval.tv_sec, (long)status.it_interval.tv_usec);
    // 2. 等待几个周期
    printf("Waiting for %d intervals...\n", num_intervals);
    int last_count = 0;
    while (atomic_load(&prof_count) < num_intervals) {
        // 可以在这里做些消耗 CPU 的工作,让 ITIMER_PROF 计时
        // 为了简单,我们用 sleep 模拟时间流逝
        // 注意:sleep 是墙钟时间,而 ITIMER_PROF 是 CPU 时间
        // 如果进程大部分时间在 sleep,ITIMER_PROF 可能不会按预期计时
        // 这里只是演示 getitimer,实际使用中要考虑时钟源
        sleep(1);
        // 检查计时器状态
        if (getitimer(ITIMER_PROF, &status) == -1) {
            perror("getitimer during loop");
        } else {
            // 只在计数变化时打印,减少输出
            int current_count = atomic_load(&prof_count);
            if (current_count != last_count) {
                printf("  After %d SIGPROF signals:\n", current_count);
                printf("    Current value: %ld.%06ld seconds\n",
                       (long)status.it_value.tv_sec, (long)status.it_value.tv_usec);
                printf("    Interval: %ld.%06ld seconds (unchanged)\n",
                       (long)status.it_interval.tv_sec, (long)status.it_interval.tv_usec);
                last_count = current_count;
            }
        }
    }
    printf("Received %d SIGPROF signals. Stopping timer.\n", num_intervals);
    // 3. 停止计时器
    struct itimerval stop_timer = {{0, 0}, {0, 0}};
    if (setitimer(ITIMER_PROF, &stop_timer, NULL) == -1) {
        perror("setitimer stop ITIMER_PROF");
    }
    // 4. 再次检查状态 (应该都是 0)
    printf("Checking timer status after stopping:\n");
    if (getitimer(ITIMER_PROF, &status) == -1) {
        perror("getitimer after stop");
    } else {
        printf("  Current value: %ld.%06ld seconds\n",
               (long)status.it_value.tv_sec, (long)status.it_value.tv_usec);
        printf("  Interval: %ld.%06ld seconds\n",
               (long)status.it_interval.tv_sec, (long)status.it_interval.tv_usec);
    }
    return 0;
}
代码解释:
- 设置 
SIGPROF信号处理函数,并使用原子变量prof_count来计数。 - 使用 
setitimer启动一个每 2 秒触发一次的周期性ITIMER_PROF计时器。 - 立即调用 
getitimer检查并打印计时器的初始状态,可以看到it_value和it_interval都被正确设置。 - 进入循环等待 
SIGPROF信号。为了简化,循环中使用sleep(1),但这并不会增加ITIMER_PROF的计时,因为sleep是墙钟时间,而ITIMER_PROF计算的是 CPU 时间。在实际性能分析中,这里应该是消耗 CPU 的工作。 - 在循环中定期调用 
getitimer,并打印剩余时间。注意it_interval始终保持不变,因为它表示的是设置的周期。 - 接收到指定数量的信号后,通过设置 
it_value和it_interval都为 0 来停止计时器。 - 最后再次调用 
getitimer,确认计时器已停止(值为 0)。 
示例 3:结合 setitimer 的 old_value 和 getitimer
这个例子演示了如何结合使用 setitimer 的 old_value 参数和 getitimer 来管理计时器状态。
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void alarm_handler(int sig) {
    write(STDERR_FILENO, "SIGALRM\n", 8);
}
void print_timer_status(const char *msg, const struct itimerval *timer) {
    printf("%s:\n", msg);
    printf("  Current value (remaining): %ld.%06ld seconds\n",
           (long)timer->it_value.tv_sec, (long)timer->it_value.tv_usec);
    printf("  Interval (reload): %ld.%06ld seconds\n",
           (long)timer->it_interval.tv_sec, (long)timer->it_interval.tv_usec);
}
int main() {
    struct itimerval initial_timer, old_timer, current_timer;
    if (signal(SIGALRM, alarm_handler) == SIG_ERR) {
        perror("signal SIGALRM");
        exit(EXIT_FAILURE);
    }
    // 1. 设置一个初始计时器 (10秒后超时,不重复)
    memset(&initial_timer, 0, sizeof(initial_timer));
    initial_timer.it_value.tv_sec = 10;
    printf("Setting initial timer for 10 seconds.\n");
    if (setitimer(ITIMER_REAL, &initial_timer, NULL) == -1) {
        perror("setitimer initial");
        exit(EXIT_FAILURE);
    }
    sleep(3); // 等待 3 秒
    // 2. 使用 setitimer 的 old_value 参数获取并保存旧设置
    struct itimerval temp_timer = {{0, 0}, {0, 0}}; // 新的临时设置 (这里设置为 0)
    printf("\nCalling setitimer to get old value (without changing timer).\n");
    // 通过设置一个 '0' 计时器并获取 old_value,可以读取当前状态
    // 但这会取消当前计时器,不太符合 '只读' 的目的
    // 更标准的 '只读' 方式是使用 getitimer
    // 让我们用更清晰的方式:先 getitimer,再用 setitimer 的 old_value
    printf("--- Correct way to get timer status ---\n");
    if (getitimer(ITIMER_REAL, ¤t_timer) == -1) {
        perror("getitimer");
        exit(EXIT_FAILURE);
    }
    print_timer_status("Status after 3 seconds (using getitimer)", ¤t_timer);
    // 3. 现在,设置一个新计时器 (5秒),并保存旧设置
    struct itimerval new_timer;
    memset(&new_timer, 0, sizeof(new_timer));
    new_timer.it_value.tv_sec = 5; // 5 秒后超时
    printf("\n--- Setting new timer (5s) and saving old setting ---\n");
    if (setitimer(ITIMER_REAL, &new_timer, &old_timer) == -1) {
        perror("setitimer with old_value");
        exit(EXIT_FAILURE);
    }
    print_timer_status("Saved old timer setting", &old_timer);
    sleep(2); // 再等待 2 秒
    // 4. 检查当前计时器状态
    if (getitimer(ITIMER_REAL, ¤t_timer) == -1) {
        perror("getitimer current");
    } else {
        print_timer_status("Current timer status (after 2s of new timer)", ¤t_timer);
    }
    printf("Waiting for new 5-second timer to expire...\n");
    pause(); // 等待 SIGALRM
    // 5. 恢复旧的计时器设置
    printf("\n--- Restoring old timer setting ---\n");
    if (setitimer(ITIMER_REAL, &old_timer, NULL) == -1) {
        perror("setitimer restore old");
        exit(EXIT_FAILURE);
    }
    if (getitimer(ITIMER_REAL, ¤t_timer) == -1) {
        perror("getitimer after restore");
    } else {
        print_timer_status("Timer status after restore", ¤t_timer);
    }
    printf("Waiting for restored timer to expire...\n");
    pause(); // 等待恢复的计时器 SIGALRM
    printf("Restored timer expired. Program finished.\n");
    return 0;
}
代码解释:
- 设置一个 10 秒后超时的初始计时器。
 - 等待 3 秒后,调用 
getitimer获取并打印当前计时器状态(剩余约 7 秒)。 - 调用 
setitimer(ITIMER_REAL, &new_timer, &old_timer):- 设置一个新的 5 秒计时器。
 - 将旧计时器的设置(剩余约 7 秒)通过 
old_value参数保存在old_timer变量中。 
 - 等待 2 秒后,再次调用 
getitimer检查当前(新)计时器的状态(剩余约 3 秒)。 - 等待新计时器超时。
 - 调用 
setitimer(ITIMER_REAL, &old_timer, NULL)将计时器恢复为之前保存的设置(约 7 秒)。 - 调用 
getitimer验证恢复是否成功。 - 等待恢复的计时器超时。
 
重要提示与注意事项:
- “只读”查询: 
getitimer是查询计时器状态的标准且推荐方式。虽然可以通过setitimer的old_value参数间接获取信息(例如设置一个 0 秒的定时器),但这通常会改变计时器状态(取消它),不符合“只读”查询的初衷。 - 精度: 
getitimer返回的时间精度是微秒(tv_usec)。 - 时钟源: 返回的 
it_value(剩余时间)是基于对应计时器的时钟源的。ITIMER_REAL是墙钟时间,ITIMER_VIRTUAL和ITIMER_PROF是 CPU 时间。 - 状态检查: 
getitimer是检查计时器是否仍在运行以及还剩多少时间的有效方法。 - 与 
setitimer配合:getitimer和setitimer经常一起使用,用于保存、恢复或动态调整计时器设置。 
总结:
getitimer 是一个专门用于查询进程间隔计时器当前状态的系统调用。它通过填充 struct itimerval 结构体,返回指定计时器的剩余时间和重载时间。理解其与 setitimer 的配合使用对于精确控制和监控基于信号的定时任务至关重要。虽然 setitimer 的 old_value 参数也能提供一些信息,但 getitimer 是进行“只读”状态查询的标准和清晰的方法。