clone()函数及其与Linux线程实现的关系

#include<sched.h>
int clone(int (*func)(void*), void *child_stack, int flags, void* fimc_arg ...);
/* pid_t *ptid, struct user_desc* tls, pid_t* ctid*/
还有三个参数在Linux2.6版本中提出,主要是为了线程的实现。
return process ID of child on success, or -1 on error
  • clone()主要用于linux线程库的实现。
  • clone创建的新进程几乎于父进程的翻版。与fork不同的是,克隆生成的进程继续运行时不会以调用处为起点,而是去调用以参数func所指定的函数,func又称为子函数
  • 进程切换:把运行的进程的CPU寄存器中的数据取出放入内核态的堆栈中,将要运行的进程的数据从内核态堆栈中取出放入CPU寄存器中(硬件上下文),还会把所有一切信息进行切换,内核为每个进程维护了一个PCB(进程控制块)用来存储进程的信息。
  • CPU在对进程进行调度的时候用的是时间片轮转的方式使多个任务在同一个CPU上执行变成了可能,时间片轮转算法进程会切换进程,导致切换中的额外开销(需要切换数据,保存信息加载信息写入等操作)。
    直接消耗:CPU寄存器需要保存加载,系统调度器的代码需要执行,TLB实例需要重新加载,CPU的pipeline需要刷掉
    间接消耗:多核cache之间的共享数据,间接消耗对于程序的影响要看线程工作区操作数据的大小。

参数flags

共享文件描述符表: CLONE_FILES

如果指定了CLONE_FILES标志,父、子进程会共享同一个打开文件描述符表。**意思就是父子进程指向的文件描述符位于同一个虚拟内存中,这样不管父子进程中谁改变了该文件描述符的性质,对方都会被影响。**如果不设置,那么就和fork之后的父子进程的文件描述符状态相同,各自的文件描述符都在各自的虚拟内存中。


共享对信号的处置设置:CLONE_SIGHAND

如果设置了CLONE_SIGHAND,那么父子进程将共享同一个信号处置表。和共享同一个文件描述符含义相似,就是父子进程中无论谁使用了sigaction或者signal函数改变对信号的处置,则对方都会被影响。如果未设置就和fork调用后的情况相同。


挂起父进程直至子进程退出或调用exec(): CLONE_VFORK
如果设置了CLONE_VFORK,父进程将一直挂起,直至子进程调用exec()或子进程结束为止。


共享进程的虚拟内存 CLONE_VM

如果设置了CLONE_VM标志,父子进程会共享同一个虚拟内存页(如同vfork())。无论哪个进程更新了内存,或是调用了mmap(),munmap(),另一个进程同样会观察到这些变化如果未设置CLONE_VM,就如同fork()。

共享同一虚拟内存是线程的关键属性之一,POSIX线程标准对此也有要求。
创建的POISX线程时总是指定了CLONE_VM标志。


线程组:CLOEN_THREAD

若设置了CLONE_THREAD,则会将子进程置于父进程的线程组中。如果未设置,那么会将子进程置于新的线程组中。

POSIX标准规定,进程的所有线程共享同一进程ID(既每个线程调用getpid()都应返回相同值),LINUX从2.4版本开始引入了线程组(threads group),以满足这一需求。

一个线程组内的所有线程拥有同一父进程ID,既线程组与首线程ID相同。**仅当线程组中所有线程都终止后,其父进程才会收到SIGCHILD信号(或其它终止信号)。**这些行为符合POSIX线程规范的要求。

从Linux2.6开始,如果设置了CLONE_THREAD,同时也必须设置CLONE_SIGHAND。这也与POSIX线程标准的深入要求相契合。


线程本地存储: CLONE_SETTLS
如果设置了CLONE_SETTLS,那么参数tls所指向的user_desc结构对线程所使用的线程本地存储缓冲区加以描述。


线程库支持的flags

  • CLONE_PARENT_SETTID 主要目的是因为ptid的值必须在clone()函数调用完成后才赋值,如果此时创建的线程销毁,那ptid还没有赋值,处理器程序就无法正确处理销毁的线程。设置了该参数后,可以保证在clone()返回之前就给ptid赋值,从而是线程库避免了这种竞争条件。

CLONE的标志使用

  • 进程:大体来说,fork()就相当于设置flags为SIGCHILD的clone调用,而vfork则相当于flags为(CLONE_VM | CLONE_VFORK | SIGCHILD)。

-NPTL线程实现则使用了clone()函数的所有七个参数来创建线程,flags设置如下:
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND | CLONE_THREAD | CLONE_SETTLS | CLONE_PARETN_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章