多线程创建:pthread()和clone()实现机制的异同
用户级线程与LWP
Pthread()是基于用户级线程来实现,而clone()是基于轻量级进程(LWP)来实现的。
对于用户级线程,是由用户空间运行线程库,使得任何应用程序都可以通过使用线程库被设计成多线程程序。所以对于线程的创建、消息的传递等都由线程库来完成,并且内核感知不到多线程的存在。而内核继续以进程为单位,给该进程一个执行状态。
而对于LWP而言,它是由内核支持的用户线程。正如图片里面显示的一样,它可以起到逻辑上对于用户线程和内核线程的连接。
事实上,它是基于内核线程的高级抽象,因此只有先支持内核线程,才会有LWP.由于LWP都与特定的内核线程关联,因此每个LWP都是独立的线程调度单元。即使有一个LWP在系统中阻塞,也不会影响到整个进程的执行。
LWP的局限性在于,大多数LWP的操作如建立、析构以及同步等,都需要经过内核的系统的调用,因此系统调用的代价比较高;需要在用户模式和内核模式中切换。
正因为系统调用的代价比较高,每个LWP都需要内核线程支持,消耗内核线程资源(栈空间),因此一个系统不能支持大量的LWP。
不同点
所以对于pthread_create(),是通过用户线程的线程库pthread来创建用户线程,由线程库调度。此时内核是感知不到用户线程的存在的。同时,根据用户线程的特点,pthread_create()创建出来的线程是可以跨操作系统运行的,并且不需要内核模式就可以实现线程的切换,极大节省了切换的开销和内核的资源。
但是对于操作系统调度的进程,每个进程只有一个pthread_create()创建出来的线程可以执行。自然,该线程阻塞,整个进程也随之阻塞。可以让进程选择不同的调度算法实现该线程,不过不能由内核调度,而是只能自己实现调度算法。
而对于clone(),创建的是一个LWP,因此对核心而言,核心是可感知的,并且由核心所调度。如果实行的是一对一的线程模型,那么此时的LWP就类似于用户线程,但由于它与一个特定的内核线程关联,因此具有部分内核线程的特点:通过clone()创建出来的LWP消耗内核栈空间,并且系统调度时需要在内核线程和用户线程之间切换,从而造成开销。但是如果创建出来的LWP在系统调用中出现了阻塞,是不会影响整个进程的执行的。
相同点
而在linux系统中,对于clone(),调用函数时如果没有设置CLONE_FS等标志,则所创建的LWP类似于进程创建的fork();设置了诸多标志后,则类似于pthread_create()。
但由于linux本身并没有线程进程的区分,而采用task任务一词,所以一般在linux系统下的pthread_create(),实际上可以看做是clone()的调用加上标志的设置,开辟了寄存器空间,栈空间,以及私有存储空间。
参考自:
https://blog.****.net/kwinway/article/details/80546210
https://blog.****.net/blog_lee/article/details/50096923
https://blog.****.net/dan15188387481/article/details/49450491
https://blog.****.net/vinter_he/article/details/79788743