全部博文(140)
分类: LINUX
2014-02-23 20:01:02
原文地址:Linux 线程分析 作者:datao0907
用户空间利用系统调用clone来创建线程,在glibc中文件夹nptl/sysdeps/pthreadcreatethread.c中的函数create_thread中指明了flags:
调用创建线程的函数:
而ARCH_CLONE定义为:
而clone函数的参数:
就是这些参数去调用do_fork函数来创建了一个线程
CLONE_VM:共享虚拟内存
CLONE_FS:共享文件命名空间,文件系统信息,以及pwd
CLONE_FILES:共享文件描述符表
CLONE_SIGNAL:POSIX信号量,具体不详,内核中没有该设置,()
CLONE_SETTLS:设置线程局部存储区域(类似pthread_setspecific,pthread_getspecific函数调用,不过该函数在用户层封装之后实现,而set/get_thread_area才是真正的系统调用)
CLONE_PARENT_SETTID:在clone 系统调用中从用户空间复制创建线程的pid:
在nptl库中等价于调用CLONE_CHILD_SETTID,因为调用的实参都相同,从nptl注释中看出它的开销很大,因此通过CLONE_PARENT_SETTID来实现。
CLONE_CHILD_SETTID:将内核态的p->set_child_tid指向用户态的child_tidptr:
当新进程执行前,又将当前进程的pid复制到该域中.
CLONE_CHILD_CLEARTID:在copy_process函数中,有同样的效果,指向child_tidptr:
但是该作用域用在当进程终止时,回收传递给用户空间的tid:
上面的标志就是创建线程的所有标志了,CLONE_CHILD_SETTID,CLONE_PARENT_SETTID在线程创建时使用,而CLONE_CHLID_CLEARTID在线程退出时采用。
内核态线程
内核态线程通常指的是内核级守护线程,主要执行下面的任务:
1.周期性与块驱动同步修改的内存页,如将脏数据回写至磁盘。
2.将内存页写至交换分区
3.实现日志文件系统的事务机制
主要分为两种类型的执行方法:
1.线程一旦启动,就进行等待直到内核要求其执行特定的任务
2.一旦创建就周期性检查各种资源,监视系统资源使用情况,超过限制时就需要采取行动,如pdflush.
创建内核线程函数如下:
由于内核线程运行在内核态中,所有没有用户栈,而且也只能访问内核的部分虚拟内存。
在定义进程时有两个域:
Linux系统中虚拟内存分为两部分:低端内存为用户程序,而高端则留给内核,当用户程序进入内核态时,用户态的内存区域指针保存在mm中,内核态程序没有用户级程序,所有mm则为空,但是由于执行系统调用之后进入内核态,或者执行内核态进程时,为了清楚知道当前用户态的进程,active_mm就指向了当前的用户空间进程,为了防止被内核态访问时,用户空间被释放,系统增加一个计数器:mm_users,而僵尸进程也只有在计数为0时才会被释放。处于进程上下文时两个指针是一样的。
内核线程能够使用两种方式来实现,通过传递一个函数指针给kernel_thread,然后调用daemonize进入守护模式:
1.如果有用户态资源,则释放用户态的所有资源,如内存上下区域,文件描述符等。
2.damonize阻塞接收所有的信号
3.将父进程设置为init
还可以通过下面的函数来创建内核线程:
该函数创建一个名称为namefmt的内核级线程,通过调用wake_up_process来启动它,运行函数threadfn(data),如果没有调用函数kthread_stop或kthread_should_stop,则调用do_exit来退出。
类似地,还可以调用kthread_run,kthread_create_on_cpu来创建线程。
可以通过调用ps -fax来查看内核线程:
[]表示内核线程/0表明该内核线程限制运行在0号cpu之上。
参考资料
professional linux kernel architecture
linux-kernel-v.2.26.4源码
glibc2.9源码
yandongxiao2014-02-23 20:08:31
CLONE_VM:共享虚拟内存
CLONE_FS:共享文件命名空间,文件系统信息,以及pwd
CLONE_FILES:共享文件描述符表
CLONE_SIGNAL:POSIX信号量,具体不详,内核中没有该设置,(CLONE_SIGHAND|CLONE_THREAD)
CLONE_SETTLS:设置线程局部存储区域(类似pthread_setspecific,pthread_getspecific函数调用,不过该函数在用户层封装之后实现,而set/get_thread_area才是真正的系统调用)
CLONE_PARENT_SETTID:在clone 系统调用中从用户空间复制创建线程的pid
这就是线程创建时,所要共享的全部内容。共享虚拟内存,共享文件描述符标,共享文件命名空间,文件系统信息,POSIX信号量都还能理解,设置线程局部存储区域即线程内部的全局变量,详细分析,看http://blog.chinaunix.net/uid-27024249-id-3937907.html