Linux <sys/time.h> 研究 timeval itimerval

 
 
 
 

Linux系统下,获取毫秒级的系统时间,使用毫秒级的定时器,修改文件访问时间等,用sys/time.h下的方法会很方便 

 


 
 
下面详细来看sys/time.h下的数据结构和方法

数据结构:

timeval:time value 存储时间格式

struct timeval {    

long tv_sec;      //

long tv_usec;    //毫秒

 

itimerval:

struct itimerval {    

struct timerval it_value;        //从设定定时器开始计算,到第一次定时器生效的时间

struct timerval it_interval;    //每两次定时器生效的时间间隔

};    

特别说明:

l 如果it_value被设为0,系统无视it_interval的值并且终止timer,所以可以通过这种方式来使timer失效

l 如果it_interval被设为0,则timer在执行一次之后失效

 

 

方法:

1. int   getitimer(int, struct itimerval *);

获取定时器,一般会有三种类型的定时器:

ITIMER_REAL:

Decrements in real time. A SIGALRM signal is delivered when this timer expires.

ITIMER_VIRTUAL:

Decrements in process virtual time. It runs only when the process is executing.  A SIGVTALRM signal is delivered when it expires.

ITIMER_PROF:

Decrements both in process virtual time and when the system is running on behalf  of the process. It is designed to be used by interpreters in statistically  profiling the execution of interpreted programs. Each time the ITIMER_PROF  timer expires, the SIGPROF signal is delivered.

例如:

如果要获得real time类型的定时器,则调用

getitimer(ITIMER_REAL, &value);

 

2. int   setitimer(int, const struct itimerval *, struct itimerval *);

设置定时器

第一个参数:定时器类型

第二个参数:指定的定时器

第三个参数:调用setitimer之前的旧定时器

3. int   gettimeofday(struct timeval *, void *);

获取毫秒级别的系统时间

如果第二个参数不为NULL,结果不可预料(If tzp is not a null pointer, the behaviour  is unspecified.)

4. int   utimes(const char *, const struct timeval [2]);

用来设定Linux系统下文件的最后访问时间和最后修改时间

第一个参数:文件路径

第二个参数:timeval[0]指的是最后访问时间

   timeval[1]指的是最后修改时间

 

 

 

 

用法详解:  

 

1.用来获取毫秒级的系统时间(197011日开始算起)

int   gettimeofday(struct timeval *, void *);

例子:gettimeofday.cpp

#include <sys/time.h>

#include <stdio.h>

#include <string.h>

 

int main()

{

struct timeval curtime;

gettimeofday(&curtime, NULL);

printf("curtime.tv_sec:%d\n", curtime.tv_sec);

printf("curtime.tv_usec:%d\n", curtime.tv_usec);

return 0;

}

 

 

 

 

2.使用定时器

例子:timer.cpp

#include <sys/time.h>

#include <stdio.h>

#include <signal.h>

#include <string.h>

#include <unistd.h>

 

void sayHello(int);

 

int main()

{

signal(SIGALRM, sayHello);

struct itimerval timer;

memset(&timer, 0, sizeof(timer));

 

timer.it_value.tv_sec = 5;

timer.it_value.tv_usec = 0;

 

timer.it_interval.tv_sec = 3;

timer.it_interval.tv_usec = 0;

 

setitimer(ITIMER_REAL, &timer, NULL);

 

while(true)

{

pause();

}

return 0;

}

 

void sayHello(int temp)

{

printf("hello world!\n");

}

 

 

 

代码详解:

使用settimer设定的timer时间到的时候,会发出SIGALRM信号,通过signal(SIGALRM,  sayHello)方法指定在收到信号时的动作。

按照代码中的设定,从settimer方法被调用开始算起,经过5秒钟第一次执行sayHello

法,之后每3秒钟执行一次sayHello

通过while(true)死循环保证进程不会终止,如果没有这个死循环,timer只会在5秒钟后响 应一次

 

 

3.修改文件最后访问时间和最后修改时间

 

 

#include <sys/time.h>

#include <stdio.h>

#include <string.h>

 

int main()

{

char path[] = "/home/mqq/jordan/try/test";

 

struct timeval times[2];

for(int i=0; i<2; i++)

{

memset(×[i], 0, sizeof(timeval));

}

 

times[0].tv_sec = 123;

times[0].tv_usec = 0;

 

 

times[1].tv_sec = 456;

times[1].tv_usec = 0;

 

utimes(path, times);

perror("error info:");

return 0;

}

 

 

stat + filename 可以查看文件上次访问时间等信息

程序执行前:

 

执行后:

 

转载于:https://www.cnblogs.com/jordan-tao/archive/2012/11/03/linux_sys_times.html

<think>我们正在处理LWIP中关于时间结构体定义冲突的问题。用户提到LWIP_TIMEVAL_PRIVATE设置为0时系统的sys/time.h头文件中的timeval结构体定义冲突。 在LWIP中,当使用socket API时,可能会用到struct timeval。如果系统已经提供了这个结构体(通常在sys/time.h中定义),而LWIP也尝试定义它,就会导致重定义错误。 解决方案:通过配置LWIP的时间结构体定义选项来解决冲突。 具体步骤: 1. 在lwipopts.h中,设置LWIP_TIMEVAL_PRIVATE=0,表示使用系统提供的timeval结构体,而不是使用LWIP内部的私有定义。 2. 但是,如果系统没有提供sys/time.h,或者提供的timeval结构体LWIP的要求不兼容,那么就需要设置LWIP_TIMEVAL_PRIVATE=1,让LWIP使用自己的定义。 然而,用户遇到的情况是:设置LWIP_TIMEVAL_PRIVATE=0时,sys/time.h冲突。这可能是由于在包含LWIP头文件之前,没有正确地包含sys/time.h,或者包含的顺序不对。 因此,我们可以这样处理: - 确保在包含LWIP头文件之前,先包含系统的sys/time.h。这样,当LWIP_TIMEVAL_PRIVATE=0时,LWIP会使用系统已经定义的timeval,而不会重复定义。 另外,注意检查编译器的包含路径,确保正确找到了sys/time.h。 如果问题仍然存在,可能是因为在同一个编译单元中,既包含了sys/time.h,又包含了LWIP的socket头文件(其中在LWIP_TIMEVAL_PRIVATE=0时,会再次包含sys/time.h),导致重复包含。这时,我们可以使用头文件保护宏来避免重复包含,或者检查LWIP的源码中是否已经做了保护。 在LWIP的socket.h中,我们可以看到如下代码(以lwip 2.1.2为例): ```c #if LWIP_TIMEVAL_PRIVATE #include <sys/time.h> #endif ``` 当LWIP_TIMEVAL_PRIVATE=0时,不会包含sys/time.h,因此不会造成重复包含。但是,用户可能在其他地方已经包含了sys/time.h,而LWIP的socket.h中又定义了自己的timeval(当LWIP_TIMEVAL_PRIVATE=1时),这就会导致冲突。 因此,正确的配置应该是: 情况1:系统提供了sys/time.h,并且我们想使用系统的timeval定义。 - 设置LWIP_TIMEVAL_PRIVATE=0 - 在包含任何LWIP头文件之前,包含<sys/time.h> 情况2:系统没有提供sys/time.h,或者我们想使用LWIP自己定义的timeval(避免系统冲突)。 - 设置LWIP_TIMEVAL_PRIVATE=1 用户的问题描述是:设置LWIP_TIMEVAL_PRIVATE=0时sys/time.h冲突。这很可能是由于在包含LWIP头文件之前没有包含sys/time.h,导致LWIP在定义timeval时,系统头文件还没有被包含,从而出现重复定义。 因此,我们建议: 在包含LWIP头文件之前,先包含系统的sys/time.h。例如: ```c #include <sys/time.h> #include "lwip/opt.h" #include "lwip/sockets.h" ``` 如果这样做了还是有重定义错误,那么可能是sys/time.h被多次包含,而缺少头文件保护。可以检查sys/time.h是否有多重包含保护,例如: ```c #ifndef _SYS_TIME_H #define _SYS_TIME_H ... // 内容 #endif ``` 如果问题仍然存在,我们可以尝试在包含sys/time.h之前定义宏来避免重复定义,但这通常不是推荐做法。 另一种情况:如果用户使用的是C++,则需要注意,C++中可能将sys/time.h包含在extern "C"块中,而LWIP的头文件可能没有,这也会导致问题。 总结: 1. 在lwipopts.h中,设置LWIP_TIMEVAL_PRIVATE=0。 2. 在包含LWIP的socket头文件之前,确保已经包含了<sys/time.h>。 3. 确保sys/time.h有正确的头文件保护。 如果用户无法修改包含顺序(比如因为第三方库的限制),那么可能需要设置LWIP_TIMEVAL_PRIVATE=1,并使用LWIP自己定义的时间结构体。但这样可能会导致系统其他部分不兼容,因为系统其他部分可能使用系统的timeval定义。 因此,优先推荐调整包含顺序。 下面我们用一个例子说明: 在main.c或者使用socket的源文件中: ```c // 首先包含系统的sys/time.h #include <sys/time.h> // 然后包含LWIP的头文件 #include "lwip/opt.h" #include "lwip/sockets.h" ``` 这样,当LWIP_TIMEVAL_PRIVATE=0时,LWIP的sockets.h中就不会再定义timeval,而是使用已经包含的sys/time.h中的定义。 如果用户使用的是裸机环境,没有sys/time.h,那么就必须设置LWIP_TIMEVAL_PRIVATE=1,让LWIP提供自己的定义。 注意:在嵌入式系统中,可能没有sys/time.h,所以需要根据目标系统进行配置。 最后,如果用户仍然遇到问题,可能需要检查具体的错误信息,看是哪个结构体重定义了,因为可能还有其他结构体(如timevaltimespec等)冲突。 根据引用[1]中的内容,我们也可以参考LWIP官方文档中关于时间结构体的配置说明。</think>### 解决 LWIP 中 `LWIP_TIMEVAL_PRIVATE` `sys/time.h` 的冲突问题 当在 LWIP 项目中遇到 `LWIP_TIMEVAL_PRIVATE=0` 系统 `sys/time.h` 头文件冲突时,根本原因是 **系统时间结构体 LWIP 私有定义的重定义冲突**。以下是完整解决方案: --- #### 问题根源分析 1. **结构体重定义冲突** LWIP 的 `timeval` 结构体定义(在 `lwip/arch.h` 中)标准 POSIX 头文件 `<sys/time.h>` 中的定义冲突: ```c // LWIP 私有定义 (lwip/arch.h) struct timeval { long tv_sec; long tv_usec; }; // 系统标准定义 (sys/time.h) struct timeval { __time_t tv_sec; // 可能使用不同基础类型 __suseconds_t tv_usec; }; ``` 2. **配置选项作用** - `LWIP_TIMEVAL_PRIVATE=1`:使用 LWIP 内部定义 - `LWIP_TIMEVAL_PRIVATE=0`:尝试使用系统定义 *冲突发生在设置为 0 时,因系统头文件未被正确处理* --- #### 分步解决方案 ##### 步骤 1:正确配置 lwipopts.h 在项目配置文件 `lwipopts.h` 中添加: ```c /* 强制使用系统头文件中的 timeval 定义 */ #define LWIP_TIMEVAL_PRIVATE 0 // 使用系统定义 #define LWIP_COMPAT_SOCKETS 0 // 禁用兼容层 ``` ##### 步骤 2:处理头文件包含顺序 在引用 LWIP 头文件**前**包含系统头文件: ```c // 在 main.c 或协议栈初始化文件中 #include <sys/time.h> // 先包含系统头文件 #include "lwip/tcpip.h" // 再包含 LWIP 头文件 #include "lwip/sockets.h" ``` ##### 步骤 3:解决类型不匹配(如有) 如果系统使用特殊类型(如 `__time_t`),在 `cc.h` 中添加类型映射: ```c // lwip/cc.h typedef __time_t time_t; // 映射系统类型 typedef __suseconds_t suseconds_t; ``` ##### 步骤 4:验证配置(关键) 在编译前检查预处理结果: ```c // 在源文件中添加临时检查 #if !defined(LWIP_TIMEVAL_PRIVATE) || (LWIP_TIMEVAL_PRIVATE != 0) #error "配置未生效!请检查 lwipopts.h" #endif ``` --- #### 冲突场景处理方案 | 场景 | 解决方案 | 适用平台 | |--------------------------|----------------------------------|----------------------| | 裸机系统无 sys/time.h | 设置 `LWIP_TIMEVAL_PRIVATE=1` | Cortex-M 裸机 | | Linux 用户态程序 | 遵循步骤 2 的头文件顺序 | Linux 应用层 | | RTOS 提供部分 POSIX 支持 | 添加步骤 3 的类型映射 | FreeRTOS、RT-Thread | | 第三方库头文件冲突 | 在冲突头文件前包含 `sys/time.h` | 所有平台 | --- #### 工作原理图解 ```mermaid graph LR A[应用程序] --> B[包含 sys/time.h] B --> C[定义系统 timeval] C --> D[包含 lwip/sockets.h] D --> E{检查 LWIP_TIMEVAL_PRIVATE} E --=0--> F[使用系统定义] E --=1--> G[使用 LWIP 私有定义] ``` --- #### 典型错误案例 **错误配置**: ```c #include "lwip/sockets.h" // 先包含 LWIP #include <sys/time.h> // 后包含系统头文件 // 触发重定义错误:struct timeval 重复定义 ``` **正确配置**: ```c #include <sys/time.h> // 先包含系统头文件 #include "lwip/sockets.h" // 再包含 LWIP // 编译通过:LWIP 复用系统定义 ``` > 通过正确处理头文件包含顺序和类型映射,可确保 LWIP 无缝集成到各类嵌入式系统中[^1]。 --- ### 相关问题 1. 如何解决 LWIP 的 `errno` 系统标准库的冲突? 2. 在资源受限系统中如何优化 LWIP 的内存分配策略? 3. LWIP 的 RAW/Callback API 和 Socket API 有何性能差异?[^1] [^1]: 参考野火《LwIP应用开发实战指南》中关于协议栈移植的章节,重点处理平台相关层(arch)的适配问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值