目錄linux
多個線程共享同一個進程的地址空間中的資源,是對一臺計算機上多個進程的模擬,有時也稱線程爲輕量級的進程。程序員
而對一臺計算機上多個進程,則共享物理內存、磁盤、打印機等其餘物理資源。多線程的運行也多進程的運行相似,是CPU在多個線程之間的快速切換。算法
不一樣的進程之間是充滿敵意的,彼此是搶佔、競爭CPU的關係,若是迅雷會和QQ搶資源。而同一個進程是由一個程序員的程序建立,因此同一進程內的線程是合做關係,一個線程能夠訪問另一個線程的內存地址,你們都是共享的,一個線程乾死了另一個線程的內存,那純屬程序員腦子有問題。小程序
相似於進程,每一個線程也有本身的堆棧,不一樣於進程,線程庫沒法利用時鐘中斷強制線程讓出CPU,能夠調用thread_yield運行線程自動放棄CPU,讓另一個線程運行。windows
線程一般是有益的,可是帶來了不小程序設計難度,線程的問題是:多線程
所以,在多線程的代碼中,須要更多的心思來設計程序的邏輯、保護程序的數據。spa
線程的實現能夠分爲兩類:用戶級線程(User-Level Thread)和內核線線程(Kernel-Level Thread),後者又稱爲內核支持的線程或輕量級進程。在多線程操做系統中,各個系統的實現方式並不相同,在有的系統中實現了用戶級線程,有的系統中實現了內核級線程。操作系統
內核的切換由用戶態程序本身控制內核切換,不須要內核干涉,少了進出內核態的消耗,但不能很好的利用多核CPU。線程
在用戶空間模擬操做系統對進程的調度,來調用一個進程中的線程,每一個進程中都會有一個運行時系統,用來調度線程。此時當該進程獲取CPU時,進程內再調度出一個線程去執行,同一時刻只有一個線程執行。設計
內核級線程:切換由內核控制,當線程進行切換的時候,由用戶態轉化爲內核態。切換完畢要從內核態返回用戶態;能夠很好的利用smp,即利用多核CPU。windows線程就是這樣的。
優勢:當有多個處理機時,一個進程的多個線程能夠同時執行。
缺點:由內核進行調度。
用戶級與內核級的多路複用,內核同一調度內核線程,每一個內核線程對應n個用戶線程。
歷史:在內核2.6之前的調度實體都是進程,內核並無真正支持線程。它是能過一個系統調用clone()來實現的,這個調用建立了一份調用進程的拷貝,跟fork()不一樣的是,這份進程拷貝徹底共享了調用進程的地址空間。LinuxThread就是經過這個系統調用來提供線程在內核級的支持的(許多之前的線程實現都徹底是在用戶態,內核根本不知道線程的存在)。很是不幸的是,這種方法有至關多的地方沒有遵循POSIX標準,特別是在信號處理,調度,進程間通訊原語等方面。
很顯然,爲了改進LinuxThread必須獲得內核的支持,而且須要重寫線程庫。爲了實現這個需求,開始有兩個相互競爭的項目:IBM啓動的NGTP(Next Generation POSIX Threads)項目,以及Redhat公司的NPTL。在2003年的年中,IBM放棄了NGTP,也就是大約那時,Redhat發佈了最初的NPTL。
NPTL最開始在redhat linux 9裏發佈,如今從RHEL3起內核2.6起都支持NPTL,而且徹底成了GNU C庫的一部分。
設計:NPTL使用了跟LinuxThread相同的辦法,在內核裏面線程仍然被看成是一個進程,而且仍然使用了clone()系統調用(在NPTL庫裏調用)。可是,NPTL須要內核級的特殊支持來實現,好比須要掛起而後再喚醒線程的線程同步原語futex.
NPTL也是一個1*1的線程庫,就是說,當你使用pthread_create()調用建立一個線程後,在內核裏就相應建立了一個調度實體,在linux裏就是一個新進程,這個方法最大可能的簡化了線程的實現。
除NPTL的1*1模型外還有一個m*n模型,一般這種模型的用戶線程數會比內核的調度實體多。在這種實現裏,線程庫自己必須去處理可能存在的調度,這樣在線程庫內部的上下文切換一般都會至關的快,由於它避免了系統調用轉到內核態。然而這種模型增長了線程實現的複雜性,並可能出現諸如優先級反轉的問題,此外,用戶態的調度如何跟內核態的調度進行協調也是很難讓人滿意。