tasklet && workqueue && kernel timer

本文详细介绍了Linux内核中的三种延时处理机制:kernel timer、tasklet和workqueue。首先,讲解了kernel timer的工作原理,包括HZ和jiffies的概念及其转换方法。接着,阐述了tasklet的使用,强调了tasklet的原子性和非并发执行特性。最后,介绍了workqueue的工作队列机制,讨论了其与tasklet的区别,以及如何创建、调度和取消工作。这些机制在驱动程序和内核开发中起到关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、kernel timer

1、适用环境
内核中许多部分的工作都高度依赖于时间信息。Linux内核利用硬件提供的不同的定时器以支持忙等待或睡眠等待等时间相关的服务。忙等待时,CPU会不断运转。但是睡眠等待时,进程将放弃CPU。因此,只有在后者不可行的情况下,才考虑使用前者。当然内核也提供了某些便利,如果我们需要在将来的某个时间点调度执行某个动作,同时在该时间点到达之前不会阻塞当前进程,则可以使用内核定时器。

2. HZ和jiffies
内核通过定时器中断来跟踪时间流。系统定时器能以可编程的频率中断处理器。此频率即为每秒的定时器节拍数,也可以说是系统时钟中断发生的频率,对应着内核变量HZ。选择合适的HZ值需要权衡。HZ值大,定时器间隔时间就小,因此进程调度的准确性会更高。但是,HZ值越大也会导致开销和电源消耗更多,因为更多的处理器周期将被耗费在定时器中断上下文中。
HZ的值取决于体系架构,而且目前内核支持无节拍的内核(CONFIG_NO_HZ),它会根据系统的负载动态触发定时器中断。
每次当时钟中断发生时,内核内部计数器的值就增加一。这个计数器的值在系统引导时被初始化为0,因此,它的值就是自上次操作系统引导以来的时钟滴答数。这个计数器是一个64位的变量(即使是在32位架构上也是64位),称为"jiffies_64",但是驱动程序开发者通常访问的是jiffies变量,它是unsigned long型的变量,要么和jiffies_64相同,要么仅仅是jiffies_64的低32位。通常首选使用jiffies,因为对它的访问很快,从而对64位jiffies_64值的访问并不需要在所有架构上都是原子的。
 因此jiffies变量记录了系统启动以来,系统定时器已经触发的次数。内核每秒钟将jiffies变量增加HZ次。因此,对于HZ值为100的系统,1个jiffy等于10ms,而对于HZ为1000的系统,1个jiffy仅为1ms。

3.比较缓存值与当前值所用到的宏

#include <linux/jiffies.h>

int time_after(unsigned long a,unsigned long b) 如果a(jiffies的某个快照)所代表的时间比b靠后,则返回真
int time_before(unsigned long a,unsigned long b) 如果a 比 b靠前,则返回真
int time_after_eq(unsigned long a,unsigned long b) 如果 a 比 b靠后或者相等,返回真
int time_before_eq(unsigned long a,unsigned long b) 如果 a 比 b靠前或者相等,返回真

4. 内核空间和用户空间时间表述方法的转换

(1) 有关时间的结构体
struct timeval
{
int tv_sec;
int tv_usec;
};
其中tv_sec是由凌晨开始算起的秒数,tv_usec则是微秒(10E-6 second)。

struct timezone
{
int tv_minuteswest;
int tv_dsttime;
};
tv_minuteswest是格林威治时间往西方的时差,tv_dsttime则是时间的修正方式。

struct timespec
{
long int tv_sec;
long int tv_nsec;
};
其中tv_sec是由凌晨开始算起的秒数,tv_nsec是nano second(10E-9 second)。

struct tm
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
tm_sec表「秒」数,在 [0,61]之间,多出来的两秒是用来处理跳秒问题用的。
tm_min表「分」数,在 [0,59]之间。
tm_hour表「时」数,在 [0,23]之间。
tm_mday表「本月第几日」,在 [1,31]之间。
tm_mon表「本年第几月」,在 [0,11]之间。
tm_year要加1900表示那一年。
tm_wday表「本第几日」,在 [0,6]之间。
tm_yday表「本年第几日」,在 [0,365]之间,
### Java 单例模式的概念 Java 中的单例模式是一种常见的设计模式,主要目的是确保整个应用程序运行期间某个类仅有一个实例存在。通过控制类的实例化过程,开发者能够有效管理全局状态并减少不必要的资源消耗[^1]。 #### 单例模式的特点 - **唯一性**:在整个应用生命周期中,某类始终只有一个实例。 - **全局访问点**:提供了统一的方式获取唯一的实例。 - **延迟加载**:通常情况下,在第一次使用时才初始化实例,从而优化性能[^3]。 --- ### Java 单例模式的实现方式 以下是几种典型的单例模式实现方式: #### 1. 饿汉式(Eager Initialization) 饿汉式是在类加载阶段就完成实例化的实现方式。由于静态变量 `instance` 被声明为 `final` 和 `static`,因此 JVM 可以保证线程安全性和唯一性。 ```java public class Singleton { private static final Singleton instance = new Singleton(); private Singleton() {} public static Singleton getInstance() { return instance; } } ``` 这种方式简单高效,但由于实例在类加载时就被创建,可能浪费资源[^2]。 --- #### 2. 懒汉式(Lazy Initialization) 懒汉式的实现会在调用 `getInstance()` 方法时首次创建实例。为了防止多线程环境下的并发问题,需加入同步机制。 ```java public class Singleton { private static Singleton instance; private Singleton() {} public synchronized static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } ``` 虽然解决了延迟加载的问题,但每次调用都需要加锁,影响效率[^4]。 --- #### 3. 双重校验锁定(Double Checked Locking) 双重校验锁定是对懒汉式的改进版本,它减少了不必要的同步操作,提高了性能。 ```java public class Singleton { private volatile static Singleton instance; // 使用volatile关键字确保可见性 private Singleton() {} public static Singleton getInstance() { if (instance == null) { // 第一次检查 synchronized (Singleton.class) { if (instance == null) { // 第二次检查 instance = new Singleton(); // 实例化对象 } } } return instance; } } ``` 此方法既实现了延迟加载,又能保证线程安全性[^5]。 --- #### 4. 枚举实现(Enum Singleton) 枚举类型的单例模式被认为是最简洁和最安全的一种实现方式,天然支持序列化和反序列化保护。 ```java public enum Singleton { INSTANCE; public void doSomething() { System.out.println("Doing something..."); } } ``` 这种实现方式不仅避免了反射攻击的风险,还简化了代码结构。 --- #### 5. 静态内部类(Static Inner Class) 利用静态内部类的特性来实现单例模式,只有当外部类的 `getInstance()` 方法被调用时才会触发内部类的加载。 ```java public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } } ``` 这种方法兼具延迟加载的优势,同时无需显式地处理线程安全问题。 --- ### 单例模式的优点与缺点 #### 优点 - 减少内存占用,节约系统资源。 - 提高性能,尤其适用于频繁创建销毁的对象。 - 统一对外接口,便于管理和维护。 #### 缺点 - 违背单一职责原则,增加耦合度。 - 不适合需要动态扩展的应用场景。 - 对于其他开发人员来说不够直观,容易引起误解。 --- ### § 1. 如何判断一个类是否适合作为单例? 2. 在分布式环境中如何实现跨进程的单例模式? 3. 如果单例类需要支持序列化功能,应该注意哪些细节? 4. 哪些实际应用场景最适合采用单例模式? 5. 反射机制是否会破坏单例模式的安全性?如果会,该如何解决?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值