内核是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。 定时器是Linux提供的一种定时服务的机制,它在某个特定的时间唤醒某个进程来进行工作。内核在时钟中断发生后检测各定时器是否到期,在linux内核中提供了一组函数和数据结构来完成定时触发工作/周期的事务。
进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。linux是一个具有保护模式的操作系统。它一直工作在i386 cpu的保护模式之下。内存被分为两个单元: 内核区域和用户区域。一般地,在使用虚拟内存技术的多任务系统上,内核和应用有不同的地址空间,因此,在内核和应用之间以及在应用与应用之间进行数据交换需要专门的机制来实现。
内核定时器是管理内核时间的基础,用来计算流逝的时间,它以某种频率(节拍率)自行触发时钟中断。内核定时器在时钟中断发生后,作为软中断在下半部的上下文钟执行的。所有的定时器结构都以链表的形式存储。时钟中断发生后,内核按链表顺序依次执行。
一般来说,定时器在超时后会立即执行,但是也有可能被推迟到下一个时钟节拍才能运行,所以不能用定时器来实现硬实时的操作。又因为内核定时器发生在软中断中,因此,定时器执行函数不能够睡眠,也不能够持有信号量。如果对硬件的访问需要使用信号量同步,或者可能睡眠(比如需要调用kmalloc内存分配,但是由于某种原因不能使用GFP_ATOMIC标志),就不能直接通过定时器来实现了。一个变通的做法是在内核定时器执行函数里调用工作队列,在工作队列处理函数中实现对硬件的访问。
Linux源代码:
#include <sys/time.h>
#include <pthread.h>
#include <stdio.h>
//声明获得时间函数
int gettimeofday(struct timeval *tv,struct timezone *tz);
//声明创建定时器函数
//int pthread_create(&id,NULL,(void *) thread,NULL);
//声明线程归并函数
//pthread_join(id,NULL);
//定义内核定时器
/***********
struct timeval{
long tv_sec; //秒数
long tv_usec; //微秒
};
***********/
//子线程
void thread(void){
int i;
for(i=0;i<3;i++)
printf("This is a pthread.\n");
}
int pthread(void){
pthread_t id; // 声明了一个pthread_t型的变量
int i,ret;
ret=pthread_create(&id,NULL,(void *) thread,NULL);
if(ret!=0){
printf("Create pthread error!\n");
exit(1);
}
for(i=0;i<3;i++)
printf("This is the main process.\n");
pthread_join(id,NULL);
return(0);
}
main(){
struct timeval tpstart,tpend;
/*申请struct timeval的变量,tv_sec返回的是秒数,tv_usec返回的是微秒数*/
float timeuse;
gettimeofday(&tpstart,NULL);
pthread();
gettimeofday(&tpend,NULL);
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+ tpend.tv_usec-tpstart.tv_usec;
timeuse/=1000000;
printf("Used Time:%f sec\n",timeuse);
exit(0);
}
调试过程:
- 打开Ubuntu虚拟机;
- 打开终端terminal;
- 输入Linux命令测试:vim timer.c,进入编辑器,编辑源程序;
- 编辑源程序结束后,输入ESC键+:wq保存并退出编辑器。
- 编译源程序,输入:gcc timer.c -lpthread -o timer.out。(使用pthread API函数,需在程序中增加头文件pthread.h,在编译时要加上-lpthread选项,pthread线程函数位于libpthread.so共享库中)。
6.输入命令./timer.out运行源程序,得到结果输出。
运行结果截图: