Linux2 6核心實現的是NPTL

2021-09-08 17:16:01 字數 4135 閱讀 6816

nptl是乙個1×1的執行緒模型,即乙個執行緒對於乙個作業系統的排程程序,優點是非常簡單。而其他一些作業系統比如solaris則是mxn的,m對應建立的執行緒數,n對應作業系統可以執行的實體。(n轉

**:全選

937   struct task_struct  ;

pid,從字面上是process id,但其實是thread id。

tgid,從字面上,應該是thread group id,也就是真正的process id。

這一點,可以從系統呼叫getpid和gettid中看出來(位於kernel/timer.c)。

**:全選

954   asmlinkage long sys_getpid(void)

955

1100  asmlinkage long sys_gettid(void)

1101

group_leader欄位,指向執行緒組中的第乙個執行緒,建立第乙個執行緒的時候,group_leader指向自己,建立其後的執行緒時,指向第乙個執行緒的task_struct結構;

thread_group,當前程序所有執行緒的佇列,對於group_leader,這是個佇列頭,對於其後的程序而言,通過這個字段,掛入佇列中,可以通過此佇列,遍歷所有執行緒。

執行緒組中各個執行緒的關係,是在do_fork中設定的,具體的**在copy_process中(位於kernel/fork.c):**:全選

959   copy_process()

960

1254     if (likely(p->pid))

...

1271     }

...

1320  }

1113-1114行說明在建立執行緒時,從父程序獲取tgid,表明他們在同乙個執行緒組中;1181-1182則對group_leader和thread_group初始化,對於第乙個執行緒,則group_leader就是它自己;1234-1236行,將新建立的執行緒的group_leader設定成為父程序得group_leader,無論父程序是不是執行緒組中的第乙個執行緒,它的group_leader都是指向第乙個執行緒的task_struct,同時通過thread_group欄位,掛入到第乙個執行緒的thread_group佇列中;1266行表明只有執行緒組中的第乙個執行緒,才會通過tasks欄位,掛入到init_task佇列中。

在引入執行緒組概念後,退出部分也引入了乙個新的系統呼叫exit_group(位於kernel/exit.c)

1055  noret_type void

1056  do_group_exit(int exit_code)

1057 

1073        spin_unlock_irq(&sighand->siglock);

1074   }

1075

1076     do_exit(exit_code);

1077     /* notreached */

1078  }

在1060行中,current->signal其實是執行緒組中所有執行緒共享的,對於呼叫exit_group的那個執行緒,如果是乙個多執行緒的程序,就會進入1062-1074這部分**,如果是單執行緒,則直接進入do_exit退出程序。這部分**的主要操作在zap_other_threads中(位於kernel/signal.c)

void zap_other_threads(struct task_struct *p)

982   

1002  }

next_thread定義在include/linux/sched.h中,如下

651  static inline struct task_struct *next_thread(const struct task_struct *p)

1652 

其實就是通過task_struct中的thread_group佇列來遍歷執行緒組中的所有執行緒。

在其中,會在signal->flags中設定signal_group_exit,同時,搜尋執行緒組中所有程序,在每個執行緒中掛上乙個sigkill訊號,這樣,當那些執行緒排程到執行的時候,就會處理sigkill訊號,對於sigkill訊號的處理,會呼叫do_group_exit,不過,當這次呼叫到do_group_exit的時候,將執行到1061行,然後就到了1076行的do_exit。這樣,當執行緒組中的每個執行緒都執行過一遍後,整個執行緒組就退出了。

posix thread library (nptl)使linux核心可以非常有效的執行使用posix執行緒標準寫的程式。這裡有乙個測試資料,在32位機下,nptl成功啟動100000個執行緒只用了2秒,而不使用nptl將需要大約15分鐘左右的時間。

歷史在核心2.6以前的排程實體都是程序,核心並沒有真正支援執行緒。它是能過乙個系統呼叫clone()來實現的,這個呼叫建立了乙份呼叫程序的拷貝,跟fork()不同的是,這份程序拷貝完全共享了呼叫程序的位址空間。linuxthread就是通過這個系統呼叫來提供執行緒在核心級的支援的(許多以前的執行緒實現都完全是在使用者態,核心根本不知道執行緒的存在)。非常不幸的是,這種方法有相當多的地方沒有遵循posix標準,特別是在訊號處理,排程,程序間通訊原語等方面。

很顯然,為了改進linuxthread必須得到核心的支援,並且需要重寫執行緒庫。為了實現這個需求,開始有兩個相互競爭的專案:ibm啟動的ngtp(next generation posix threads)專案,以及redhat公司的nptl。在2023年的年中,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裡就是乙個新程序,這個方法最大可能的簡化了執行緒的實現。

有乙個問題一直沒有想清楚,請教牛人,謝謝。

資源描述:

系統環境:4個cpu, linux2.6核心,nptl,smp。

問題:(程序是資源單元;執行緒是執行單元。)

乙個程序擁有4個執行緒,這4個執行緒同時在4個cpu上執行。

問1:系統的排程單位是程序還是執行緒呢?(針對linux2.6核心);

問2:如果排程單位是執行緒,每個執行緒都應該執行在同乙個程序的上下文中,如果這樣的話就需要對程序上下文加鎖;同時如果有其他程序的執行緒也執行在同乙個cpu上,那麼程序的上下文切換會非常頻繁?

如果排程單位是程序,又沒有辦法解釋同乙個程序中的4個執行緒同時跑在4個cpu上?

問3:看到一篇文章說「smp的負載均衡是按程序數計算的」不知道是否正確。

如果正確,同乙個程序的所有執行緒應該分配到同乙個cpu上,不解?

答:問題1:

linux核心中的排程單位總是乙個程序。但是核心中有對執行緒的支援。

問題2:

既然在linux的執行緒就是乙個程序.就不存在什麼所有執行緒都在同一程序上下文。而且這個觀點是錯誤的。乙個執行緒是什麼?執行緒只是乙個程序的子集。也就是說是乙個程序上下文的子集。而且每個執行緒的上下文的很少有交集。除非兩個執行緒之間需要通訊。linux中程序所傳建的執行緒本質就是程序。只不過這些子程序和父程序看到的都是同一位址空間,共享資源。 恢復乙個執行緒的執行只需要恢復執行緒上下文。既然是執行緒在執行,何來程序上下文? 執行緒的實現方式不同.但原理本質一樣。 既然linux的排程單位是程序,而執行緒又是以程序實現的.所以程序的四個執行緒在4個cpu上同時執行是可能的.只要不存在互斥。

問題3:

這個是高階問題... 不清楚...樓主可以goolge下.應該很多文章和**的。

Linux 2 6核心編譯,核心公升級

本文描述了在fc8下公升級linux核心為2.6.25的詳細步驟.1.首先從如下 得到linux 2.6.25.2.然後在 usr src下untar這個包.tar xjfv linux 2.6.25.tar.bz2 3.配置核心 cd usr src linux 2.6.25 make mrpro...

Linux2 6核心啟動分析

我們已知u boot的終極目的是啟動核心,那麼核心啟動的開始必定是u boot傳入的引數。開啟armlinux.c 發現有一行的 為 thekernel 0,bd bi arch number,bd bi boot params 帶入三個引數 第乙個引數是0,第二個引數是機器id,第三個引數是引數所...

Linux 2 6 核心驅動移植

隨著 linux 2.6的發布,由於2.6核心做了教的改動,各個裝置的 驅動程式在不同程度上要進行改寫。為了方便各位linux愛好者我把自己整理的這分文件share出來。該文當列舉了2.6核心同以前版本的絕大多數變化,可惜的是由於時間和精力有限沒有詳細列出各個函式的用法。1 使用新的入口 必須包含 ...