在linux内核中,所谓的内核线程实际上是一个共享父进程地址空间的进程,它有自己的系统堆栈;所以它们依然是一个进程,只不过这些进程可以与其他进程共享某些资源,这里的其他进程也是所谓的线程。
1 内核线程与普通进程的异同 1.1 内核线程没有自己的地址空间,所以它们的"current->mm"都是空的;
1.2 内核线程只能在内核空间操作,不能与用户空间交互;
1.3 跟普通进程一样,内核线程也有优先级和被调度。
2 内核线程创建 在内核中,有两种方法可以生成内核线程,一种是使用kernel_thread()接口,另一种是用kthread_create()接口。
先说kernel_thread接口,使用该接口创建的线程,必须在该线程中调用daemonize()函数,这是因为只有当线程的父进程指向"Kthreadd"时,该线程才算是内核线程,而恰好daemonize()函数主要工作便是将该线程的父进程改成“kthreadd"内核线程;默认情况下,调用deamonize()后,会阻塞所有信号,如果想操作某个信号可以调用allow_signal()函数。
而kthread_create接口,则是标准的内核线程创建接口,只须调用该接口便可创建内核线程;默认创建的线程是存于不可运行的状态,所以需要在父进程中通过调用wake_up_process()函数来启动该线程。
3 内核线程的退出 当线程执行到函数末尾时会自动调用内核中do_exit()函数来退出或其他线程调用kthread_stop()来指定线程退出。
4 内核线程接口 4.1 kernel_thread接口
- int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
// fn为线程函数,arg为线程函数参数,flags为标记
- void daemonize(const char * name,...); // name为内核线程的名称
注:这里的flags的取值为
- CSIGNAL /* signal mask to be sent at exit */
- CLONE_VM /* set if VM shared between processes */
- CLONE_FS /* set if fs info shared between processes */
- CLONE_FILES /* set if open files shared between processes */
- CLONE_SIGHAND /* set if signal handlers and blocked signals shared */
- CLONE_PTRACE /* set if we want to let tracing continue on the child too */
- CLONE_VFORK /* set if the parent wants the child to wake it up on mm_release */
- CLONE_PARENT /* set if we want to have the same parent as the cloner */
- CLONE_THREAD /* Same thread group? */
- CLONE_NEWNS /* New namespace group? */
- CLONE_SYSVSEM /* share system V SEM_UNDO semantics */
- CLONE_SETTLS /* create a new TLS for the child */
- CLONE_PARENT_SETTID /* set the TID in the parent */
- CLONE_CHILD_CLEARTID /* clear the TID in the child */
- CLONE_DETACHED /* Unused, ignored */
- CLONE_UNTRACED /* set if the tracing process can't force CLONE_PTRACE
- on this clone */
- CLONE_CHILD_SETTID /* set the TID in the child */
- CLONE_NEWUTS /* New utsname group? */
- CLONE_NEWIPC /* New ipcs */
- CLONE_NEWUSER /* New user namespace */
- CLONE_NEWPID /* New pid namespace */
- CLONE_NEWNET /* New network namespace */
- CLONE_IO /* Clone io context */
4.2 kthread_create接口
- struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,
- const char namefmt[], ...);
-
//threadfn为线程函数;data为线程函数参数;namefmt为线程名称,可被格式化的
- int wake_up_process(struct task_struct *p); //唤醒线程
- struct task_struct *kthread_run(int (*threadfn)(void *data),void *data,
- const char namefmt[], ...);//是以上两个函数的功能的总和
注:因为线程也是进程,所以其结构体也是使用进程的结构体"struct task_struct"。
5 示例代码 kthread.rar - #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/kthread.h>
-
- MODULE_LICENSE("Dual BSD/GPL");
- MODULE_AUTHOR("Kozo");
-
- static int noop(void *dummy)
- {
- int i = 0;
- daemonize("mythread"); /*使用kernel_thread创建的线程,需要调用该函数*/
- while(i++ < 5)
- {
- printk("my thread:current->mm = %p\n",current->mm);
- printk("my thread:current->active_mm = %p\n",current->active_mm);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(10*HZ);
- }
- return 0;
- }
-
- static int noop2(void *dummy)
- {
- int i = 0;
- while(i++ < 5)
- {
- printk("my thread:current->mm = %p\n",current->mm);
- printk("my thread:current->active_mm = %p\n",current->active_mm);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(10*HZ);
- }
- return 0;
- }
- static __init int demo_init(void)
- {
-
- printk(KERN_INFO"demo init\n");
- printk("demo init:current->mm = %p\n",current->mm);
- printk("demo init:current->active_mm = %p\n",current->active_mm);
- //kernel_thread(noop, NULL, CLONE_KERNEL|SIGCHLD);
- kthread_run(noop2,NULL,"mythread");
- return 0;
- }
-
- static __exit void demo_exit(void)
- {
- printk(KERN_INFO"demo exit\n");
- }
-
- module_init(demo_init);
- module_exit(demo_exit);
6 执行结果从结果可以看出,子线程的地址空间是没有的。
转载请注明出处:
add358.blog.chinaunix.net
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。