linux子線程
Ⅰ linux怎麼查看線程阻塞原因
linux查看線程阻塞原因:pthread_join一般主線程來調用,用來等待子線程退出,因為是等待,所以是阻塞的,一般主線程會依次join所有它創建的子線程。
1)執行top命令,或使用-H選項(顯示所有線程),找到相關的高CPU的PID。
2)生成thread mp 快照(kill -3 PID)。
3)將top命令輸出PID轉換為HEX格式(16進制)。
4)在thread mp data中搜索nid=<Hex PID>。
5)分析受影響的thread和stack trace,精確定位代碼。
特點:
Linux,全稱GNU/Linux,是一套免費使用和自由傳播的類Unix操作系統,是一個基於POSIX的多用戶、多任務、支持多線程和多CPU的操作系統。伴隨著互聯網的發展,Linux得到了來自全世界軟體愛好者、組織、公司的支持。
它除了在伺服器方面保持著強勁的發展勢頭以外,在個人電腦、嵌入式系統上都有著長足的進步。使用者不僅可以直觀地獲取該操作系統的實現機制,而且可以根據自身的需要來修改完善Linux,使其最大化地適應用戶的需要。
Linux不僅系統性能穩定,而且是開源軟體。其核心防火牆組件性能高效、配置簡單,保證了系統的安全。在很多企業網路中,為了追求速度和安全,Linux不僅僅是被網路運維人員當作伺服器使用,甚至當作網路防火牆,這是Linux的一大亮點。
Linux具有開放源碼、沒有版權、技術社區用戶多等特點,開放源碼使得用戶可以自由裁剪,靈活性高,功能強大,成本低。尤其系統中內嵌網路協議棧,經過適當的配置就可實現路由器的功能。這些特點使得Linux成為開發路由交換設備的理想開發平台。
Ⅱ linux中線程如何指定內核
Linux線程指定內核的第一步就是就要先查查到內核所在的文件的位置,通過操作系統進行調度。
第二步,指定內核,就是要默認它的內核系統,是通過搜索引擎文件查找CPU的信息,然後通過指定的內核的進項文件進行調度,最終再進行定位,找到指定內核。
第三步,平時應用程序在運行時,都是由操作系統管理的。操作系統對應用進程進行調度,使其在不同的核上輪番運行。過程中就會使用到縣城所包含的文件了。
第四步,對於普通的應用,操作系統的默認調度機制是沒有問題的。
第五步,但是,當某個進程需要較高的運行效率時,就有必要考慮將其綁定到單獨的核上運行,以減小由於在不同的核上調度造成的開銷,就需要指定固定的內核了。
第六步,隨後,把某個進程/線程綁定到特定的cpu核上後,該進程就會一直在此核上運行,不會再被操作系統調度到其他核上。
但綁定的這個核上還是可能會被調度運行其他應用程序的。
第七步具體的操作方法是使用cat/proc/cpuinfo查看cpu信息。
隨後,指定程序運行,比如->%taskset-pc12726,pid2726scurrentaffinitylist:0,1,pid2726snewaffinitylist:1,採用固定的循環運行方式,這樣就能夠指定程序內核了。
Ⅲ 在windows中的進程、線程和在linux中的進程、線程有什麼區別
對於windows來說,進程和線程的概念都是有著明確定義的,進程的概念對應於一個程序的運行實例(instance),而線程則是程序代碼執行的最小單元。CreateThread()用於建立一個新的線程,傳遞線程函數的入口地址和調用參數給新建的線程,然後新線程就開始執行了。
windows下,一個典型的線程擁有自己的堆棧、寄存器(包括程序計數器PC,用於指向下一條應該執行的指令在內存中的位置),而代碼段、數據段、打開文件這些進程級資源是同一進程內多個線程所共享的。因此同一進程的不同線程可以很方便的通過全局變數(數據段)進行通信,大家都可以對數據段進行讀寫,這很方便,也被在安全性方面詬病,因為它要求程序員時刻意識到這些數據不是線程獨立的。
對於linux來說,則沒有很明確的進程、線程概念。首先linux只有進程而沒有線程,然而它的進程又可以表現得像windows下的線程。linux利用fork()和exec函數族來操作多進程。fork()函數可以在進程執行的任何階段被調用,一旦調用,當前進程就被分叉成兩個進程——父進程和子進程,兩者擁有相同的代碼段和暫時相同的數據段(雖然暫時相同,但從分叉開的時刻就是邏輯上的兩個數據段了,之所以說是邏輯上的,是因為這里是「寫時復制」機制,也就是,除非萬不得已有一個進程對數據段進行了寫操作,否則系統不去復制數據段,這樣達到了負擔最小),兩者的區別在於fork()函數返回值,對於子進程來說返回為0,對於父進程來說返回的是子進程id,因此可以通過if(fork()==0)…else…來讓父子進程執行不同的代碼段,從而實現「分叉」。
而linux下的進程不能像windows下線程那樣方便地通信,因為他們沒有共享數據段、地址空間等。它們之間的通信是通過所謂IPC(InterProcess Communication)來進行的。具體有管道(無名管道用於父子進程間通信,命名管道可以用於任意兩個進程間的通信)、共享內存(一個進程向系統申請一塊可以被共享的內存,其它進程通過標識符取得這塊內存,並將其連接到自己的地址空間中,效果上類似於windows下的多線程間的共享數據段),信號量,套接字。
Ⅳ linux下線程屬性常用操作有哪些
LinuxThread的線程機制
LinuxThreads是目前Linux平台上使用最為廣泛的線程庫,由Xavier Leroy ([email protected]) 負責開發完成,並已綁定在GLIBC中發行。它所實現的就是基於核心輕量級進程的"一對一"線程模型,一個線程實體對應一個核心輕量級進程,而線程之間的 管理在核外函數庫中實現。
1.線程描述數據結構及實現限制
LinuxThreads定義了一個struct _pthread_descr_struct數據結構來描述線程,並使用全局數組變數 __pthread_handles來描述和引用進程所轄線程。在__pthread_handles中的前兩項,LinuxThreads定義了兩個全 局的系統線程:__pthread_initial_thread和__pthread_manager_thread,並用 __pthread_main_thread表徵__pthread_manager_thread的父線程(初始為 __pthread_initial_thread)。
struct _pthread_descr_struct是一個雙環鏈表結構,__pthread_manager_thread所在的鏈表僅包括它 一個元素,實際上,__pthread_manager_thread是一個特殊線程,LinuxThreads僅使用了其中的errno、p_pid、 p_priority等三個域。而__pthread_main_thread所在的鏈則將進程中所有用戶線程串在了一起。經過一系列 pthread_create()之後形成的__pthread_handles數組將如下圖所示:
圖2 __pthread_handles數組結構
新創建的線程將首先在__pthread_handles數組中占據一項,然後通過數據結構中的鏈指針連入以__pthread_main_thread為首指針的鏈表中。這個鏈表的使用在介紹線程的創建和釋放的時候將提到。
LinuxThreads遵循POSIX1003.1c標准,其中對線程庫的實現進行了一些范圍限制,比如進程最大線程數,線程私有數據區大小等等。在 LinuxThreads的實現中,基本遵循這些限制,但也進行了一定的改動,改動的趨勢是放鬆或者說擴大這些限制,使編程更加方便。這些限定宏主要集中 在sysdeps/unix/sysv/linux/bits/local_lim.h(不同平台使用的文件位置不同)中,包括如下幾個:
每進程的私有數據key數,POSIX定義_POSIX_THREAD_KEYS_MAX為128,LinuxThreads使用 PTHREAD_KEYS_MAX,1024;私有數據釋放時允許執行的操作數,LinuxThreads與POSIX一致,定義 PTHREAD_DESTRUCTOR_ITERATIONS為4;每進程的線程數,POSIX定義為64,LinuxThreads增大到1024 (PTHREAD_THREADS_MAX);線程運行棧最小空間大小,POSIX未指定,LinuxThreads使用 PTHREAD_STACK_MIN,16384(位元組)。
2.管理線程
"一對一"模型的好處之一是線程的調度由核心完成了,而其他諸如線程取消、線程間的同步等工作,都是在核外線程庫中完成的。在LinuxThreads 中,專門為每一個進程構造了一個管理線程,負責處理線程相關的管理工作。當進程第一次調用pthread_create()創建一個線程的時候就會創建 (__clone())並啟動管理線程。
在一個進程空間內,管理線程與其他線程之間通過一對"管理管道(manager_pipe[2])"來通訊,該管道在創建管理線程之前創建,在成功啟動 了管理線程之後,管理管道的讀端和寫端分別賦給兩個全局變數__pthread_manager_reader和 __pthread_manager_request,之後,每個用戶線程都通過__pthread_manager_request向管理線程發請求, 但管理線程本身並沒有直接使用__pthread_manager_reader,管道的讀端(manager_pipe[0])是作為__clone ()的參數之一傳給管理線程的,管理線程的工作主要就是監聽管道讀端,並對從中取出的請求作出反應。
創建管理線程的流程如下所示:
(全局變數pthread_manager_request初值為-1)
圖3 創建管理線程的流程
初始化結束後,在__pthread_manager_thread中記錄了輕量級進程號以及核外分配和管理的線程id, 2*PTHREAD_THREADS_MAX+1這個數值不會與任何常規用戶線程id沖突。管理線程作為pthread_create()的調用者線程的 子線程運行,而pthread_create()所創建的那個用戶線程則是由管理線程來調用clone()創建,因此實際上是管理線程的子線程。(此處子 線程的概念應該當作子進程來理解。)
__pthread_manager()就是管理線程的主循環所在,在進行一系列初始化工作後,進入while(1)循環。在循環中,線程以2秒為 timeout查詢(__poll())管理管道的讀端。在處理請求前,檢查其父線程(也就是創建manager的主線程)是否已退出,如果已退出就退出 整個進程。如果有退出的子線程需要清理,則調用pthread_reap_children()清理。
然後才是讀取管道中的請求,根據請求類型執行相應操作(switch-case)。具體的請求處理,源碼中比較清楚,這里就不贅述了。
3.線程棧
在LinuxThreads中,管理線程的棧和用戶線程的棧是分離的,管理線程在進程堆中通過malloc()分配一個THREAD_MANAGER_STACK_SIZE位元組的區域作為自己的運行棧。
用戶線程的棧分配辦法隨著體系結構的不同而不同,主要根據兩個宏定義來區分,一個是NEED_SEPARATE_REGISTER_STACK,這個屬 性僅在IA64平台上使用;另一個是FLOATING_STACK宏,在i386等少數平台上使用,此時用戶線程棧由系統決定具體位置並提供保護。與此同 時,用戶還可以通過線程屬性結構來指定使用用戶自定義的棧。因篇幅所限,這里只能分析i386平台所使用的兩種棧組織方式:FLOATING_STACK 方式和用戶自定義方式。
在FLOATING_STACK方式下,LinuxThreads利用mmap()從內核空間中分配8MB空間(i386系統預設的最大棧空間大小,如 果有運行限制(rlimit),則按照運行限制設置),使用mprotect()設置其中第一頁為非訪問區。該8M空間的功能分配如下圖:
圖4 棧結構示意
低地址被保護的頁面用來監測棧溢出。
對於用戶指定的棧,在按照指針對界後,設置線程棧頂,並計算出棧底,不做保護,正確性由用戶自己保證。
不論哪種組織方式,線程描述結構總是位於棧頂緊鄰堆棧的位置。
4.線程id和進程id
每個LinuxThreads線程都同時具有線程id和進程id,其中進程id就是內核所維護的進程號,而線程id則由LinuxThreads分配和維護。
Ⅳ linux下多進程或者多線程編程的問題。新手,望指教!
你好,多進程或多線程,都不會阻塞當前語句代碼。為了您的理解,我就大膽舉下面兩個例子:
多進程:你可以看成是本來是一條路的,現在從中間拆成兩條,然後每一條路都有屬於自己這條路的代碼在運行。
多線程:你可以看成是一條路,然後分出車道,比如左車道和右車道甚至是停車道,然後每條車道都單獨通車,其他車道的不能對這條車道進行干擾。
所以,把一條路從中間拆成兩條,成本是很高的。但是把一條路分車道,成本就不是很高了。
對於您提出的main函數的疑問,當main函數最後執行完畢,程序退出後,所有的進程包括線程,都會被關閉的,哪怕你的程序中沒有關閉,操作系統也會幫你關閉的,現在的操作系統都非常的完善了。當然,也存在有線程或進程不被釋放的特殊情況,最好在編程中要記得釋放。