目录
- 一、linux 创建内核线程
- 1.1 kthread_create
- 1.2 kthread_create_worker + kthread_queue_work
- 二、设置线程优先级和调度策略
- 2.1 sched_setscheduler
- 2.2 调度策略
一、linux 创建内核线程
1.1 kthread_create
在 linux 中,可以使用 kthread_create
接口创建内核线程,该接口原型如下:
struct task_struct *kthread_create(int (*threadfn)(void *data), void *data, const char namefmt[], ...);
入参含义:
- threadfn:线程函数的入口点。
- data:传递给线程函数的参数。
- namefmt:线程的名字,可以用格式化字符串指定。
示例代码:
#include <linux/kthread.h>
#include <linux/delay.h>// 线程函数
int thread_function(void *data) {while (!kthread_should_stop()) {// 线程的主要工作pr_info("Thread is running\n");ssleep(5); // 休眠5秒}return 0;
}// 在合适的地方创建线程
struct task_struct *task;
task = kthread_create(thread_function, NULL, "my_thread");
if (!IS_ERR(task)) {wake_up_process(task); // 启动线程
}
1.2 kthread_create_worker + kthread_queue_work
kthread_create_worker
主要用于创建一个用于管理工作队列的工作线程。
函数原型:
struct kthread_worker *kthread_create_worker(unsigned int flags, const char namefmt[], ...);
入参含义:
- flags:创建worker时的标志。
- namefmt:worker的名称。
kthread_queue_work
用于将一个工作项添加到由kthread_worker
管理的工作队列中。
函数原型:
void kthread_queue_work(struct kthread_worker *worker, struct kthread_work *work);
入参含义:
-worker:目标worker。
-work:要执行的工作。
示例代码:
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>static struct kthread_worker *worker;
static struct kthread_work work;void work_function(struct kthread_work *work) {pr_info("Work function is running\n");
}int __init my_module_init(void) {worker = kthread_create_worker(0, "my_worker");if (IS_ERR(worker)) {pr_err("Failed to create kthread worker\n");return PTR_ERR(worker);}// 初始化工作kthread_init_work(&work, work_function);// 将工作排队kthread_queue_work(worker, &work);return 0;
}void __exit my_module_exit(void) {kthread_destroy_worker(worker);
}module_init(my_module_init);
module_exit(my_module_exit);
上述示例代码中,
kthread_create_worker
创建一个工作队列kthread_worker
;kthread_queue_work
将一个工作项kthread_work
添加到工作队列kthread_worker
;- 每调用一次
kthread_queue_work(worker, &work);
,工作项kthread_work
对应的执行函数work_function
就会得到一次调用。
二、设置线程优先级和调度策略
2.1 sched_setscheduler
sched_setscheduler
接口是 linux 内核中,设置特定线程或进程优先级和调度策略的接口。函数原型:
int sched_setscheduler(struct task_struct *p, int policy, const struct sched_param *param);
入参说明
- p:指向目标任务(线程或进程)的 task_struct 结构体的指针。
- policy:调度策略。
- param:指向 sched_param 结构体的指针,包含了调度参数,如优先级。
kthread_create_worker + sched_setscheduler 创建线程并设置调度策略和优先级:
static int __init my_module_init(void) {struct sched_param param;int ret;// 创建内核线程工作队列my_worker = kthread_create_worker(0, "my_worker");// 获取内核线程的task_structmy_worker_thread = my_worker->task;// 设置调度策略和优先级param.sched_priority = MAX_RT_PRIO - 1; // 设置为最高实时优先级ret = sched_setscheduler(my_worker_thread, SCHED_FIFO, ¶m);return 0;
}
kthread_create + sched_setscheduler 创建线程并设置调度策略和优先级:
// 线程函数
static int thread_function(void *data) {while (!kthread_should_stop()) {}return 0;
}static int __init my_module_init(void) {struct sched_param param;int ret;// 创建内核线程my_thread = kthread_create(thread_function, NULL, "my_thread");// 设置调度策略和优先级param.sched_priority = MAX_RT_PRIO - 1; // 设置为最高实时优先级ret = sched_setscheduler(my_thread, SCHED_FIFO, ¶m);// 启动内核线程wake_up_process(my_thread);return 0;
}
2.2 调度策略
-
SCHED_NORMAL:普通调度策略,也称为 SCHED_OTHER。Linux 默认的普通任务调度策略,基于时间片轮转调度算法,适用于大多数用户进程和内核线程。
-
SCHED_FIFO:先进先出调度策略。使用该策略时,系统优先调用高优先级的任务,想通优先级的任务按照先到先服务的顺序执行,只有在队列中所有优先级最高的任务都执行完或者放弃 CPU 后,才会执行其他任务。优先级使用 sched_param 结构中的 sched_priority 成员设置,值越小优先级越高(0 最高)。
-
SCHED_RR:循环调度策略。优先高优先级任务+相同优先级先进先出+每个任务时间片轮转,类似于 SCHED_FIFO,但每个任务有一个时间片,如果任务在该时间片内没有运行完毕,会将任务移到队列末尾等待下一轮调度。也可以通过 sched_param 结构的 sched_priority 设置优先级。
-
SCHED_BATCH:用于低优先级任务的批处理。用于大量计算密集型任务,通常在系统负载较低时,调度器会执行 SCHED_BATCH 线程。
-
SCHED_IDLE:专为低优先级的后台任务设计。只有在没有其他更重要的任务需要执行时,才会考虑执行 SCHED_IDLE 线程。
-
SCHED_DEADLINE:允许任务在预定的截止时间内完成执行,以满足实时系统对任务响应时间的严格要求。deadline 调度策略为每个任务分配固定的 CPU 时间片(Budget),并指定每个周期内允许执行的最大时间量(Period)。
参考:
SCHED_FIFO与SCHED_OTHER调度机制
【Linux 内核】进程管理 - 进程优先级 ② ( prio 调度优先级 | static_prio 静态优先级 | normal_prio 正常优先级 | rt_priority 实时优先级 )