新聞中心
在Linux中,進程是計算機程序的基本執(zhí)行單元,而線程是進程內(nèi)部的并發(fā)執(zhí)行流。線程能夠共享進程的資源,如內(nèi)存空間、文件句柄等。在這種情況下,它們可以協(xié)同工作,以便高效地完成任務。

盡管Linux內(nèi)核直接支持多線程應用程序,但創(chuàng)建一個線程并不是容易的。許多程序員對它感到困惑,因為Linux中線程的實際實現(xiàn)可能與其他操作系統(tǒng)不同。在本文中,我們將介紹Linux中創(chuàng)建線程的方法,以及如何在程序中正確使用它們。
Linux中的線程是什么?
在Linux中,線程是一種輕量級的進程。每個線程都有自己的??臻g,但與進程不同,它們共享相同的地址空間。這意味著,線程能夠訪問相同的變量、函數(shù)以及文件等,從而可以在處理相同的數(shù)據(jù)時協(xié)作工作。
一個進程創(chuàng)建的線程被稱為子線程,它們運行在相同的上下文中,但它們有自己的堆棧。進程本身也有一個主線程,它是之一個線程,它在進程初始化時自動創(chuàng)建。
Linux中創(chuàng)建線程的方法
在Linux中,應用程序可以使用線程API創(chuàng)建線程。常見的API包括pthread_create()和clone()。
pthread_create()
pthread_create()是一個庫函數(shù),允許我們在進程中創(chuàng)建多個線程。它可以創(chuàng)建一個新的線程,并附加到進程中。它的語法如下:
int pthread_create(pthread_t* thread, const pthread_attr_t* attr,void* (*start_routine)(void*), void* arg);
此函數(shù)的之一個參數(shù)為線程標識符pthread_t,它是一個變量,用于存儲創(chuàng)建的線程的唯一標識符。第二個參數(shù)為線程的屬性,我們通常將其設(shè)置為NULL。第三個參數(shù)是一個指向函數(shù)的指針,該函數(shù)是新線程的開始函數(shù)。第四個參數(shù)是該函數(shù)的參數(shù),傳遞給線程函數(shù)的參數(shù)。
以下是使用pthread_create()函數(shù)創(chuàng)建并啟動一個簡單線程的示例:
#include
#include
void *print_message_function( void *ptr );
int mn()
{
pthread_t thread1, thread2;
char *message1 = “Thread 1”;
char *message2 = “Thread 2”;
int iret1, iret2;
// 創(chuàng)建線程1
iret1 = pthread_create( &thread1, NULL, print_message_function, (void*) message1);
// 創(chuàng)建線程2
iret2 = pthread_create( &thread2, NULL, print_message_function, (void*) message2);
// 等待線程1執(zhí)行完
pthread_join( thread1, NULL);
// 等待線程2執(zhí)行完
pthread_join( thread2, NULL);
printf(“Thread 1 returns: %d\n”,iret1);
printf(“Thread 2 returns: %d\n”,iret2);
}
void *print_message_function( void *ptr )
{
char *message;
message = (char *) ptr;
printf(“%s \n”, message);
}
在上述代碼中,我們創(chuàng)建了兩個線程thread1和thread2,并分別將它們賦值為參數(shù)。然后,使用pthread_create()函數(shù)創(chuàng)建線程,并將線程函數(shù)指針和參數(shù)傳遞給函數(shù)。然后,我們等待線程執(zhí)行完,并檢查線程返回的值。
clone()
另一個創(chuàng)建線程的函數(shù)是clone()。它類似于pthread_create(),但它更為底層。clone()函數(shù)必須顯式提供線程棧和堆棧的空間。以下是一個使用clone()函數(shù)創(chuàng)建線程的示例:
#define _GNU_SOURCE /* 包含clone()函數(shù) */
#include
#include
#define STACK_SIZE 1024*1024
static char child_stack[STACK_SIZE];
void* child_fn(void* arg)
{
printf(“Child %ld running in new namespace\n”, (long)getpid());
return NULL;
}
int mn()
{
pid_t child_pid = clone(child_fn,child_stack+STACK_SIZE,SIGCHLD,NULL);
printf(“clone()=%ld\n”, (long)child_pid);
getchar(); /* 繼續(xù)運行以查看輸出結(jié)果 */
return 0;
}
在上述代碼中,我們使用了clone()函數(shù)來創(chuàng)建新的進程,并將創(chuàng)建的新進程的地址存儲在變量child_pid中。線程函數(shù)為child_fn()。
線程常見問題
創(chuàng)建線程時有許多問題,包括如何同步線程、如何處理線程處理的異常,如何避免線程之間的競爭等。以下是一些常見的線程問題:
線程同步
線程同步是一個重要的問題,因為如果多個線程同時訪問共享資源,會出現(xiàn)數(shù)據(jù)不一致的問題。因此,使用線程同步技術(shù)來協(xié)調(diào)并發(fā)線程非常重要,以避免這種沖突。線程同步包括鎖、條件變量和信號量等。
線程異常
當線程中的一個操作無法執(zhí)行時,例如分配內(nèi)存失敗或輸入格式不正確時,線程將返回異常。這時,應該為線程實現(xiàn)一個錯誤處理功能,以便在發(fā)生異常時能夠及時處理錯誤信息。
線程競爭
如果兩個或更多線程在同一時間訪問同一數(shù)據(jù),就會發(fā)生競爭。這可能導致數(shù)據(jù)丟失,死鎖和其他問題。線程競爭可以通過正確實現(xiàn)線程同步來避免。
結(jié)論
相關(guān)問題拓展閱讀:
- linux進程、線程及調(diào)度算法(三)
linux進程、線程及調(diào)度算法(三)
調(diào)度策略值得是大家都在ready時,并且CPU已經(jīng)被調(diào)度時,決定誰來運行,誰來被調(diào)度。
兩者之間有一定矛盾。
響應的優(yōu)化,意味著高優(yōu)先級會搶占優(yōu)先級,會花時間在上下文切換,會影響吞吐。
上下文切換的時間是很短的,幾微妙就能搞定。上下文切換本身對吞吐并多大影響,
重要的是,切換后引起的cpu 的 cache miss.
每次切換APP, 數(shù)據(jù)都要重新load一次。
Linux 會盡可能的在響應與吞吐之間尋找平衡。比如在編譯linux的時候,會讓你選擇 kernal features -> Preemption model.
搶占模型會影響linux的調(diào)度算法。
所以 ARM 的架構(gòu)都是big+LITTLE, 一個很猛CPU+ 多個 性能較差的 CPU, 那么可以把I/O型任務的調(diào)度指源 放在 LITTLE CPU上。需要計算的放在big上。
早期2.6 內(nèi)核將優(yōu)先級劃分了bit的優(yōu)先級。數(shù)值越低,優(yōu)先級越高。0-99優(yōu)先級 都是 RT(即時響應)的 ,都是非RT的,即normal。
調(diào)度的時候 看哪個bitmap 中的 優(yōu)先級上有任務ready??赡芏鄠€任務哦。
在普通優(yōu)先級線程調(diào)度中,高優(yōu)先級并不代表對低優(yōu)先級的絕對優(yōu)勢。會在不同優(yōu)先級進行輪轉(zhuǎn)。
就是比101高,101也會比102高,但100 不會堵著101。
眾絲進程在輪轉(zhuǎn)時,優(yōu)先級高的:
初始唯并態(tài)設(shè)置nice值為0,linux 會探測 你是喜歡睡眠,還是干活。越喜歡睡,linux 越獎勵你,優(yōu)先級上升(nice值減少)。越喜歡干活,優(yōu)先級下降(nice值增加)。所以一個進程在linux中,干著干著 優(yōu)先級越低,睡著睡著 優(yōu)先級越高。
后期linux補丁中
紅黑樹,數(shù)據(jù)結(jié)構(gòu), 左邊節(jié)點小于右邊節(jié)點
同時兼顧了 CPU/IO 和 nice。
數(shù)值代表著 進程運行到目前為止的virtual runtime 時間。
(pyhsical runtime) / weight * 1024(系數(shù))。
優(yōu)先調(diào)度 節(jié)點值(vruntime)最小的線程。權(quán)重weight 其實有nice 來控制。
一個線程一旦被調(diào)度到,則物理運行時間增加,vruntime增加,往左邊走。
weight的增加,也導致vruntime減小,往右邊走。
總之 CFS讓線程 從左滾到右,從右滾到左。即照顧了I/O(喜歡睡,分子小) 也 照顧了 nice值低(分母高).所以 由喜歡睡,nice值又低的線程,最容易被調(diào)度到。
自動調(diào)整,無需向nice一樣做出獎勵懲罰動作,個人理解權(quán)重其實相當于nice
但是 此時 來蔽拍一個 0-99的線程,進行RT調(diào)度,都可以瞬間秒殺你!因為人家不是普通的,是RT的!
一個多線程的進程中,每個線程的調(diào)度的策略 如 fifo rr normal, 都可以不同。每一個的優(yōu)先級都可以不一樣。
實驗舉例, 創(chuàng)建2個線程,同時開2個:
運行2次,創(chuàng)建兩個進程
sudo renice -n -5(nice -5級別) -g(global), 會明顯看到 一個進程的CPU占用率是另一個的 3倍。
為什么cpu都已經(jīng)達到200%,為什么系統(tǒng)不覺得卡呢?因為,我們的線程在未設(shè)置優(yōu)先級時,是normal調(diào)度模式,且是
CPU消耗型
調(diào)度級別其實不高。
利用chrt工具,可以將進程 調(diào)整為 50 從normal的調(diào)度策略 升為RT (fifo)級別的調(diào)度策略,會出現(xiàn):
chrt , nice renice 的調(diào)度策略 都是以線程為單位的,以上 設(shè)置的將進程下的所有線程進行設(shè)置nice值
線程是調(diào)度單位,進程不是,進程是資源封裝單位!
兩個同樣死循環(huán)的normal優(yōu)先級線程,其中一個nice值降低,該線程的CPU 利用率就會比另一個CPU的利用率高。
關(guān)于linux 進程中創(chuàng)建線程的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務提供商,擁有超過10年的服務器租用、服務器托管、云服務器、虛擬主機、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗。專業(yè)提供云主機、虛擬主機、域名注冊、VPS主機、云服務器、香港云服務器、免備案服務器等。
網(wǎng)站標題:Linux中進程如何創(chuàng)建線程(linux進程中創(chuàng)建線程)
文章地址:http://m.fisionsoft.com.cn/article/dpdiojh.html


咨詢
建站咨詢
