一个简单的linux内核线程的例子,根据精通linux设备驱动上的代码整合而成。
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kthread.h>
MODULE_LICENSE("GPL");
static DECLARE_WAIT_QUEUE_HEAD(myevent_waitqueue); //声明了一个等待队列头,我们可以将要睡眠的进程放入本列表
static struct task_struct * task_test;
static int mykthread(void* unused) //内核线程实体程序
{
DECLARE_WAITQUEUE(wait, current); //用本进程创建一个等待队列结点
daemonize("mykthread"); //执行线程的初始工作,然后将本线程的父线程改为kthreadd, 本线程名设为"mythread"
allow_signal(SIGKILL); //由于daemonize默认情况下会阻止所有信号,所以如果要接收某种信号,这里要手动添加
add_wait_queue(&myevent_waitqueue, &wait);// 将本进程假如等待队列
while(true)
{
printk("<0> enter while");
set_current_state(TASK_INTERRUPTIBLE); //状态被置为TASK_INTERRUPTIBLE ,则信号唤醒进程。
// 即为伪唤醒(唤醒不是因为事件的发生),因此检查并处理信号。
printk("<0> before schedule");
schedule(); //这将导致调度器从运行队列中选择一个新的任务投入运行
printk("<0> before signal_pending");
if(signal_pending(current))//判断是否有信号要处理,如果有,跳出循环,线程结束
{
break;
}
printk("<0> can trige some expand process");
}
set_current_state(TASK_RUNNING); //将当前进程的状态设为Running
remove_wait_queue(&myevent_waitqueue, &wait);// 从等待队列中移除
return 0;
}
static int __init begin(void)
{
printk("<0> module start\n");
EXPORT_SYMBOL(myevent_waitqueue);//导出myevent_waitqueue,可以让其他程序出发
task_test = kthread_create(mykthread, NULL, "mykthread");//创建一个内核线程
if(IS_ERR(task_test))
{
return PTR_ERR(task_test);
}
wake_up_process(task_test); //启动内核线程
printk("<0> init module end\n");
return 0;
}
static void __exit end(void)
{
printk("<0> module end\n");
}
module_init(begin);
module_exit(end);
触发程序
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
extern wait_queue_head_t myevent_waitqueue;
static int __init begain(void)
{
printk("<0> trigger begain ");
wake_up_interruptible(&myevent_waitqueue);//将等待队列唤醒
return 0;
}
static void __exit end(void)
{
printk("<0> trigger end\n");
}
module_init(begain);
module_exit(end);
这个程序的运行结果是:内核线程运行到 printk("<0> before schedule")后进入schedule(), 然后睡眠。直到触发程序加载,然后完成一次循环,停在下次循环的schedule()处。