国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Linux】Linux線程概念和線程控制

這篇具有很好參考價(jià)值的文章主要介紹了【Linux】Linux線程概念和線程控制。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、Linux線程概念

1.什么是線程

線程是進(jìn)程內(nèi)的一個(gè)執(zhí)行流。

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

我們知道,一個(gè)進(jìn)程會(huì)有對(duì)應(yīng)的PCB,虛擬地址空間,頁(yè)表以及映射的物理內(nèi)存。所以我們把這一個(gè)整體看做一個(gè)進(jìn)程,即進(jìn)程=內(nèi)核數(shù)據(jù)結(jié)構(gòu)+進(jìn)程對(duì)應(yīng)的代碼和數(shù)據(jù)。我們可以這樣看待虛存:虛擬內(nèi)存決定了進(jìn)程能夠看到的"資源"。因?yàn)槊恳粋€(gè)進(jìn)程都有對(duì)應(yīng)的虛擬內(nèi)存,所以進(jìn)程具有獨(dú)立性,從而進(jìn)程需要通信的前提是看到同一份資源。我們fork創(chuàng)建子進(jìn)程的時(shí)候,會(huì)將父進(jìn)程的PCB的內(nèi)容,進(jìn)程地址空間和頁(yè)表都給子進(jìn)程拷貝一份。那么我們可不可以創(chuàng)建多個(gè)PCB,而這些PCB使用同一個(gè)進(jìn)程地址空間和頁(yè)表,這樣就可以看到同一份資源了,這就是線程。

線程是進(jìn)程內(nèi)的一個(gè)執(zhí)行流,線程咋進(jìn)程內(nèi)運(yùn)行,線程在進(jìn)程的地址空間內(nèi)運(yùn)行,擁有該進(jìn)程的一部分資源。線程是CPU調(diào)度的基本單位。進(jìn)程是承擔(dān)系統(tǒng)資源的基本實(shí)體,內(nèi)部可以有一個(gè)或多個(gè)執(zhí)行流。因?yàn)槲覀兛梢酝ㄟ^(guò)虛擬地址空間+頁(yè)表的方式對(duì)進(jìn)程的資源進(jìn)行劃分,單個(gè)"進(jìn)程"(線程)執(zhí)行粒度,一定要比之前的進(jìn)程要細(xì)。

如果我們OS系統(tǒng)真的要專門設(shè)計(jì)線程的概念,OS系統(tǒng)未來(lái)就需要對(duì)線程進(jìn)行管理,就需要先描述,再組織,即一定要為線程設(shè)計(jì)專門的數(shù)據(jù)結(jié)構(gòu)表示線程對(duì)象TCB。但是線程和進(jìn)程一樣都需要被執(zhí)行,被調(diào)度(id,狀態(tài),優(yōu)先級(jí),上下文,?!?,二者十分相似,所以單純從線程調(diào)度角度,線程和進(jìn)程有很多的地方是重疊的。所以Linux工程師不想給"線程"專門設(shè)計(jì)對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu),而是直接復(fù)用PCB,用PCB用來(lái)表示Linux內(nèi)部的"線程",所以在Linux中,進(jìn)程我們稱為輕量級(jí)進(jìn)程。而windows有單獨(dú)的TCB結(jié)構(gòu)

總結(jié):

1.Linux內(nèi)核中沒(méi)有真正意義是線程,Linux是用進(jìn)程的PCB來(lái)進(jìn)行模擬,是一種完全屬于自己的一套線程方案

2.站在CPU視角,每一個(gè)PCB,都可以稱之為輕量級(jí)進(jìn)程

3.Linux線程是CPU調(diào)度的基本單位,而進(jìn)程是承擔(dān)資源分配的基本單位

4.進(jìn)程用來(lái)整體申請(qǐng)資源,線程用來(lái)伸手向進(jìn)程要資源

5.在一個(gè)程序里的一個(gè)執(zhí)行路線就叫做線程(thread)。更準(zhǔn)確的定義是:線程是“一個(gè)進(jìn)程內(nèi)部的控制序列”

6.一切進(jìn)程至少都有一個(gè)執(zhí)行線程

7.線程在進(jìn)程內(nèi)部運(yùn)行,本質(zhì)是在進(jìn)程地址空間內(nèi)運(yùn)行

8.在Linux系統(tǒng)中,在CPU眼中,看到的PCB都要比傳統(tǒng)的進(jìn)程更加輕量化

9.透過(guò)進(jìn)程虛擬地址空間,可以看到進(jìn)程的大部分資源,將進(jìn)程資源合理分配給每個(gè)執(zhí)行流,就形成了線程執(zhí)行流

Linux內(nèi)核中沒(méi)有真正意義是線程,所以Linux便無(wú)法直接提供創(chuàng)建線程的系統(tǒng)調(diào)用接口,而只能給我們提供創(chuàng)建輕量級(jí)進(jìn)程的接口,但是操作系統(tǒng)只認(rèn)線程,用戶(程序員)也只認(rèn)線程,所以Linux在軟件層給我們提供了一個(gè)原生的線程庫(kù)。

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

任何Linux操作系統(tǒng),都必須默認(rèn)攜帶這個(gè)原生線程庫(kù)–用戶級(jí)線程庫(kù)

這里我們先見(jiàn)一見(jiàn)線程:

#include <iostream>
#include <cassert>
#include <unistd.h>
#include <pthread.h>

using namespace std;

void *start_routine(void *args)
{
    while (true)
    {
        cout << "我是新線程, 我正在運(yùn)行! " << endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, start_routine, (void *)"thread one");
    assert(0 == n);
    (void)n;

    while (true)
    {
        cout << "我是主線程, 我正在運(yùn)行!" << endl;
        sleep(1);
    }
    return 0;
}

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

運(yùn)行結(jié)果:

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

我們可以看到,有兩個(gè)執(zhí)行流在運(yùn)行,這兩個(gè)執(zhí)行流的PID相同,而L不相同,其中LWP為light weight process為輕量級(jí)進(jìn)程ID,我們知道線程的CPU調(diào)度的基本單位,那么就需要唯一的標(biāo)識(shí)符,LWP就是線程的唯一標(biāo)識(shí)符。

CPU調(diào)度的時(shí)候以LWP為標(biāo)識(shí)符唯一的表示一個(gè)執(zhí)行流

當(dāng)我們只要一個(gè)執(zhí)行流的時(shí)候:

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

此時(shí)PID==LWP

注意:

線程一旦被創(chuàng)建,幾乎所有的資源都是被線程所共享的

線程也一定要有自己的私有資源:PCB私有,私有上下文結(jié)構(gòu),每一個(gè)線程都有自己獨(dú)立的棧結(jié)構(gòu)

線程切換和進(jìn)程切換相比,線程之間的切換需要操作系統(tǒng)做的工作要少很多:

1.進(jìn)程:切換頁(yè)表 && 虛擬地址空間 && 切換PCB &&上下文切換

2.線程:切換PCB &&上下文切換

3.線程切換,cache不用太更新,進(jìn)程切換需要全部更新。根據(jù)局部性原理我們知道,加載數(shù)據(jù)的時(shí)候會(huì)把需要訪問(wèn)的數(shù)據(jù)的周圍數(shù)據(jù)也加載進(jìn)去,所以執(zhí)行流運(yùn)行一段時(shí)間之后,cache里保存了許多熱點(diǎn)數(shù)據(jù),線程又使用相同的虛擬地址空間,所以線程切換的時(shí)候cache里面的數(shù)據(jù)就不用太更新,而進(jìn)程是使用不同的虛擬地址空間,所以進(jìn)程間切換的時(shí)候,需要重新加載數(shù)據(jù)

2.線程的優(yōu)缺點(diǎn)

線程的優(yōu)點(diǎn)

創(chuàng)建一個(gè)新線程的代價(jià)要比創(chuàng)建一個(gè)新進(jìn)程小得多

與進(jìn)程之間的切換相比,線程之間的切換需要操作系統(tǒng)做的工作要少很多

線程占用的資源要比進(jìn)程少很多

能充分利用多處理器的可并行數(shù)量

在等待慢速I/O操作結(jié)束的同時(shí),程序可執(zhí)行其他的計(jì)算任務(wù)

計(jì)算密集型應(yīng)用,為了能在多處理器系統(tǒng)上運(yùn)行,將計(jì)算分解到多個(gè)線程中實(shí)現(xiàn)

I/O密集型應(yīng)用,為了提高性能,將I/O操作重疊。線程可以同時(shí)等待不同的I/O操作。

線程的缺點(diǎn)

性能損失

一個(gè)很少被外部事件阻塞的計(jì)算密集型線程往往無(wú)法與共它線程共享同一個(gè)處理器。如果計(jì)算密集型線程的數(shù)量比可用的處理器多,那么可能會(huì)有較大的性能損失,這里的性能損失指的是增加了額外的同步和調(diào)度開銷,而可用的資源不變。

健壯性降低

編寫多線程需要更全面更深入的考慮,在一個(gè)多線程程序里,因時(shí)間分配上的細(xì)微偏差或者因共享了不該共享的變量而造成不良影響的可能性是很大的,換句話說(shuō)線程之間是缺乏保護(hù)的。

缺乏訪問(wèn)控制

進(jìn)程是訪問(wèn)控制的基本粒度,在一個(gè)線程中調(diào)用某些OS函數(shù)會(huì)對(duì)整個(gè)進(jìn)程造成影響。

編程難度提高

編寫與調(diào)試一個(gè)多線程程序比單線程程序困難得多

3.線程異常

單個(gè)線程如果出現(xiàn)除零,野指針問(wèn)題導(dǎo)致線程崩潰,進(jìn)程也會(huì)隨著崩潰,因?yàn)樾盘?hào)在整體發(fā)給進(jìn)程的

線程是進(jìn)程的執(zhí)行分支,線程出異常,就類似進(jìn)程出異常,進(jìn)而觸發(fā)信號(hào)機(jī)制,終止進(jìn)程,進(jìn)程終止,該進(jìn)程內(nèi)的所有線程也就隨即退出

#include <iostream>
#include <cassert>
#include <unistd.h>
#include <pthread.h>

using namespace std;

void *start_routine(void *args)
{
    while (true)
    {
        cout << "我是新線程, 我正在運(yùn)行! " << endl;
        sleep(1);
        int *p = nullptr;
        *p = 0;
    }
}

int main()
{
    pthread_t tid;
    int n = pthread_create(&tid, nullptr, start_routine, (void *)"thread one");
    assert(0 == n);
    (void)n;

    while (true)
    {
        cout << "我是主線程, 我正在運(yùn)行!" << endl;
        sleep(1);
    }
    return 0;
}

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

4.線程用途

合理的使用多線程,能提高CPU密集型程序的執(zhí)行效率

合理的使用多線程,能提高IO密集型程序的用戶體驗(yàn)(如生活中我們一邊寫代碼一邊下載開發(fā)工具,就是多線程運(yùn)行的一種表現(xiàn))

5.Linux進(jìn)程VS線程

進(jìn)程是資源分配的基本單位

線程是調(diào)度的基本單位

線程共享進(jìn)程數(shù)據(jù),但也擁有自己的一部分?jǐn)?shù)據(jù):

線程ID

一組寄存器

errno

信號(hào)屏蔽字

調(diào)度優(yōu)先級(jí)

進(jìn)程的多個(gè)線程共享 同一地址空間,因此Text Segment、Data Segment都是共享的,如果定義一個(gè)函數(shù),在各線程

中都可以調(diào)用,如果定義一個(gè)全局變量,在各線程中都可以訪問(wèn)到,除此之外,各線程還共享以下進(jìn)程資源和環(huán)境:

文件描述符表

每種信號(hào)的處理方式(SIG_ IGN、SIG_ DFL或者自定義的信號(hào)處理函數(shù))

當(dāng)前工作目錄

用戶id和組id

進(jìn)程和線程的關(guān)系如下圖:

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

二、線程控制

1.線程創(chuàng)建

POSIX線程庫(kù)

與線程有關(guān)的函數(shù)構(gòu)成了一個(gè)完整的系列,絕大多數(shù)函數(shù)的名字都是以“pthread_”打頭的

要使用這些函數(shù)庫(kù),要通過(guò)引入頭文<pthread.h>

鏈接這些線程函數(shù)庫(kù)時(shí)要使用編譯器命令的“-lpthread”選項(xiàng)

創(chuàng)建線程函數(shù)接口 – pthread_create

功能:創(chuàng)建一個(gè)新的線程
原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(*start_routine)(void*), void *arg);
參數(shù)
thread:返回線程ID
attr:設(shè)置線程的屬性,attr為NULL表示使用默認(rèn)屬性
start_routine:是個(gè)函數(shù)地址,線程啟動(dòng)后要執(zhí)行的函數(shù)
arg:傳給線程啟動(dòng)函數(shù)的參數(shù)
返回值:成功返回0;失敗返回錯(cuò)誤碼

錯(cuò)誤檢查:

傳統(tǒng)的一些函數(shù)是,成功返回0,失敗返回-1,并且對(duì)全局變量errno賦值以指示錯(cuò)誤。

pthreads函數(shù)出錯(cuò)時(shí)不會(huì)設(shè)置全局變量errno(而大部分其他POSIX函數(shù)會(huì)這樣做)。而是將錯(cuò)誤代碼通過(guò)返回值返回

pthreads同樣也提供了線程內(nèi)的errno變量,以支持其它使用errno的代碼。對(duì)于pthreads函數(shù)的錯(cuò)誤,建議通過(guò)返回值業(yè)判定,因?yàn)樽x取返回值要比讀取線程內(nèi)的errno變量的開銷更小

我們這里創(chuàng)建10個(gè)進(jìn)程,打印相關(guān)信息,主要是線程的tid

#include <iostream>
#include <cassert>
#include <unistd.h>
#include <vector>
#include <pthread.h>

using namespace std;

#define NUM 10
class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};

void *start_routine(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args);
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread create success, name: " << td->namebuffer << " cnt: " << cnt-- << endl;
        sleep(1);
    }

    return nullptr;
}

int main()
{
    vector<ThreadData *> threads;
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer, sizeof(td->namebuffer), "thread:%d", i + 1);
        pthread_create(&td->tid, nullptr, start_routine, td);
        threads.push_back(td);

        sleep(1);
    }

    for (auto &iter : threads)
    {
        cout << "create thread: " << iter->namebuffer << " : " << iter->tid << " suceesss" << endl;
    }
    return 0;
}

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

tid這么大的數(shù)字是什么呢,其實(shí)它是進(jìn)程地址空間上的一個(gè)地址

我們知道,Linux中的線程使用的是原生線程庫(kù),那么,在原生線程庫(kù)中就可能會(huì)存在多個(gè)線程,此時(shí)就需要對(duì)線程進(jìn)行管理,管理的方法是先描述再組織。在Linux中,用戶級(jí)線程,用戶關(guān)系的線程屬性在庫(kù)中,內(nèi)核中提供執(zhí)行流的調(diào)度。Linux用戶級(jí)線程:內(nèi)核輕量級(jí)進(jìn)程 = 1 : 1。

那么用戶級(jí)線程的tid究竟是什么呢,是庫(kù)中描述線程結(jié)構(gòu)體的起始地址。所以pthread_t 到底是什么類型呢?取決于實(shí)現(xiàn)。對(duì)于Linux目前實(shí)現(xiàn)的NPTL實(shí)現(xiàn)而言,pthread_t類型的線程ID,本質(zhì)就是一個(gè)進(jìn)程地址空間上的一個(gè)地址。

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

每一個(gè)結(jié)構(gòu)體就相當(dāng)于一個(gè)線程控制塊TCB,然后再使用數(shù)組進(jìn)行管理,就完成了對(duì)線程的管理

線程ID及進(jìn)程地址空間布局

pthread_ create函數(shù)會(huì)產(chǎn)生一個(gè)線程ID,存放在第一個(gè)參數(shù)指向的地址中。該線程ID和前面說(shuō)的線程ID不是一回事。

前面講的線程ID屬于進(jìn)程調(diào)度的范疇。因?yàn)榫€程是輕量級(jí)進(jìn)程,是操作系統(tǒng)調(diào)度器的最小單位,所以需要一個(gè)數(shù)值來(lái)唯一表示該線程。

pthread_ create函數(shù)第一個(gè)參數(shù)指向一個(gè)虛擬內(nèi)存單元,該內(nèi)存單元的地址即為新創(chuàng)建線程的線程ID,屬于NPTL線程庫(kù)的范疇。線程庫(kù)的后續(xù)操作,就是根據(jù)該線程ID來(lái)操作線程的。

線程庫(kù)NPTL提供了pthread_ self函數(shù),可以獲得線程自身的ID:

獲取線程ID函數(shù)接口–pthread_self

#include <pthread.h>
pthread_t pthread_self(void);
返回值是線程的id

2.線程終止

如果需要只終止某個(gè)線程而不終止整個(gè)進(jìn)程,可以有三種方法:

1.從線程函數(shù)return。這種方法對(duì)主線程不適用,從main函數(shù)return相當(dāng)于調(diào)用exit。

2.線程可以調(diào)用pthread_ exit終止自己。

3.一個(gè)線程可以調(diào)用pthread_ cancel終止同一進(jìn)程中的另一個(gè)線程。

1.從線程函數(shù)return終止線程

從線程函數(shù)return之后終止進(jìn)程就相當(dāng)于函數(shù)調(diào)用完畢,線程終止

void *start_routine(void *args)
{
    string name = static_cast<char*>(args);
    int cnt = 10;
    while (cnt)
    {
        cout << "thread name: " << name << " cnt: " << cnt-- << endl;
        sleep(1);
    }

    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    pthread_join(tid,nullptr);
    return 0;
}

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

2.調(diào)用pthread_ exit終止線程

pthread_exit函數(shù)

功能:線程終止
原型
void pthread_exit(void *value_ptr);
參數(shù)
value_ptr:value_ptr不要指向一個(gè)局部變量。
返回值:無(wú)返回值,跟進(jìn)程一樣,線程結(jié)束的時(shí)候無(wú)法返回到它的調(diào)用者(自身)

需要注意,pthread_exit或者return返回的指針?biāo)赶虻膬?nèi)存單元必須是全局的或者是用malloc分配的,不能在線程函數(shù)的棧上分配,因?yàn)楫?dāng)其它線程得到這個(gè)返回指針時(shí)線程函數(shù)已經(jīng)退出了。

void *start_routine(void *args)
{
    string name = static_cast<char*>(args);
    int cnt = 10;
    while (cnt)
    {
        cout << "thread name: " << name << " cnt: " << cnt-- << endl;
        if(cnt<5)
        {
            pthread_exit(nullptr);
        }
        sleep(1);
    }

    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid,nullptr,start_routine,(void*)"thread one");
    
    while (true)
    {
        cout << "new thread create success, name: main thread" << endl;
        sleep(1);
    }
    pthread_join(tid,nullptr);
    return 0;
}

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

為什么我們不直接只有exit結(jié)束呢,而還要提供一個(gè)pthread_exit函數(shù)來(lái)終止線程,因?yàn)閑xit是通過(guò)發(fā)送信號(hào)的方式來(lái)終止的,但是信號(hào)是整體發(fā)給進(jìn)程的,如果使用exit的話,主線程和新線程都會(huì)退出

3.調(diào)用pthread_ cancel終止線程

pthread_cancel函數(shù)

功能:取消一個(gè)執(zhí)行中的線程
原型
int pthread_cancel(pthread_t thread);
參數(shù)
thread:線程ID
返回值:成功返回0;失敗返回錯(cuò)誤碼

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

3.線程等待

為什么需要線程等待?

線程也是需要等待的,如果不進(jìn)行等待,那么就會(huì)像僵尸進(jìn)程一樣,導(dǎo)致內(nèi)存泄漏。

所以線程也必須進(jìn)行等待:1.獲取新線程的退出信息 2.回收新線程對(duì)應(yīng)的PCB等內(nèi)核資源,防止內(nèi)存泄漏

已經(jīng)退出的線程,其空間沒(méi)有被釋放,仍然在進(jìn)程的地址空間內(nèi)。

創(chuàng)建新的線程不會(huì)復(fù)用剛才退出線程的地址空間。

pthread_join函數(shù)接口

功能:等待線程結(jié)束
原型
int pthread_join(pthread_t thread, void **value_ptr);
參數(shù)
thread:線程ID
value_ptr:它指向一個(gè)指針,后者指向線程的返回值
返回值:成功返回0;失敗返回錯(cuò)誤碼
調(diào)用該函數(shù)的線程將掛起等待,直到id為thread的線程終止。thread線程以不同的方法終止,通過(guò)pthread_join得到的

我們發(fā)現(xiàn)value_ptr的類型是二級(jí)指針,而start_routine函數(shù)的返回值是void*,那么會(huì)不會(huì)start_routine的返回值就是線程的退出信息呢,答案是是的。本質(zhì)是從庫(kù)中獲取執(zhí)行線程的退出結(jié)果

#include <iostream>
#include <cassert>
#include <unistd.h>
#include <vector>
#include <pthread.h>

using namespace std;

#define NUM 10
class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};

class returnCode
{
public:
    int exit_code;
    int exit_result;
};

void *start_routine(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args);
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread create success, name: " << td->namebuffer << " cnt: " << cnt-- << endl;
        sleep(1);
    }

    return (void*)td->number;
}

int main()
{
    vector<ThreadData *> threads;
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        td->number = i + 1;
        snprintf(td->namebuffer, sizeof(td->namebuffer), "thread:%d", i + 1);
        pthread_create(&td->tid, nullptr, start_routine, td);
        threads.push_back(td);

        sleep(1);
    }

    for (auto &iter : threads)
    {
        void *ret = nullptr;
        int n = pthread_join(iter->tid, (void **)&ret);
        assert(n == 0);
        cout << "join : " << iter->namebuffer << " sucess,exit_code: " << (long long)ret << endl;
        delete iter;
    }
    return 0;
}

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

我們可以返回假的地址,整數(shù),對(duì)空間的地址,對(duì)象的地址,棧上的地址都能夠返回。

class ThreadReturn
{
public:
    int exit_code;
    int exit_result;
};
return (void *)td->number; // warning, void *ret = (void*)td->number;
return (void *)100;
pthread_exit((void *)111); // 既然假的地址,整數(shù)都能被外部拿到,那么如何返回的是,堆空間的地址呢?對(duì)象的地址呢?
ThreadReturn *tr = new ThreadReturn();
tr->exit_code = 1;
tr->exit_result = 100;

ThreadReturn tr; // 在棧上開辟的空間 return &tr;

return (void *)100; // 右值

我們需要注意的是:

我們使用一個(gè)void* ret來(lái)接收返回值,在函數(shù)pthread_join(tid,(void**)&ret)傳遞ret的地址進(jìn)去,在start_routine函數(shù)中返回的是(void*)100;所以void** p = &ret; 而(void*) x = (void*)100;那么*p = x。

所以ret = x。

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

終止?fàn)顟B(tài)是不同的,總結(jié)如下:

1.如果thread線程通過(guò)return返回,value_ ptr所指向的單元里存放的是thread線程函數(shù)的返回值。

2.如果thread線程被別的線程調(diào)用pthread_ cancel異常終掉,value_ ptr所指向的單元里存放的是常數(shù)

PTHREAD_ CANCELED。

3.如果thread線程是自己調(diào)用pthread_exit終止的,value_ptr所指向的單元存放的是傳給pthread_exit的參數(shù)。

4.如果對(duì)thread線程的終止?fàn)顟B(tài)不感興趣,可以傳NULL給value_ ptr參數(shù)。

為什么沒(méi)有見(jiàn)到,線程退出的時(shí)候,對(duì)應(yīng)的退出信號(hào)??? 線程出異常,收到信號(hào),整個(gè)進(jìn)程都會(huì)退出!
pthread_join:默認(rèn)就認(rèn)為函數(shù)會(huì)調(diào)用成功!不考慮異常問(wèn)題,異常問(wèn)題是你進(jìn)程該考慮的問(wèn)題!

4.線程分離

線程是可以等待的,等待的時(shí)候,join是阻塞式等待,如果我們不想等待呢。我們可以將線程設(shè)置為分離狀態(tài)。

默認(rèn)情況下,新創(chuàng)建的線程是joinable的,線程退出后,需要對(duì)其進(jìn)行pthread_join操作,否則無(wú)法釋放資源,從而造成系統(tǒng)泄漏。

如果不關(guān)心線程的返回值,join是一種負(fù)擔(dān),這個(gè)時(shí)候,我們可以告訴系統(tǒng),當(dāng)線程退出時(shí),自動(dòng)釋放線程資源。

pthread_detach函數(shù)接口

功能:線程分離
原型
int pthread_detach(pthread_t thread);
thread:線程ID
返回值:成功返回0;失敗返回錯(cuò)誤碼

可以是線程組內(nèi)其他線程對(duì)目標(biāo)線程進(jìn)行分離,也可以是線程自己分離:

pthread_detach(pthread_self());

joinable和分離是沖突的,一個(gè)線程不能既是joinable又是分離的。

void *start_routine(void *args)
{
    string threadname = static_cast<char *>(args);
    pthread_detach(pthread_self()); // 設(shè)置為分離狀態(tài)
    int cnt = 5;
    while (cnt--)
    {
        cout << threadname << " running " << endl;
        sleep(1);
    }

    return nullptr;
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread one");
    
    cout << "main thread running..." << endl;

    //一個(gè)線程默認(rèn)是joinable,如果設(shè)置的分離狀態(tài),就不能夠進(jìn)行等待了
    int n = pthread_join(tid, nullptr);
    cout << "result: " << n << " : " << strerror(n) << endl;
    return 0;
}

線程未分離之前:

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

這是正常的退出。

將線程進(jìn)行分離:

【Linux】Linux線程概念和線程控制,Linux系統(tǒng)編程,服務(wù)器,Linux,線程,pthread_create,線程分離,線程控制,線程概念

此時(shí)就出現(xiàn)了錯(cuò)誤,印證了線程自己分離之后主線程再進(jìn)行join。

如果沒(méi)有出現(xiàn)錯(cuò)誤,那么原因是我們無(wú)法判斷那個(gè)執(zhí)行流先運(yùn)行,如果是主線程先運(yùn)行,在新線程還沒(méi)有分離之前,主線程就已經(jīng)join處于阻塞狀態(tài),那么新線程進(jìn)行分離之后,主線程就無(wú)法得知,因?yàn)橹骶€程處于阻塞狀態(tài),那么也就不會(huì)發(fā)生錯(cuò)誤,我們可以讓主線程sleep(2),或者在主線程中創(chuàng)建線程之后就直接進(jìn)行分離。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-763041.html

到了這里,關(guān)于【Linux】Linux線程概念和線程控制的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux C/C++ 多線程TCP/UDP服務(wù)器 (監(jiān)控系統(tǒng)狀態(tài))

    Linux C/C++ 多線程TCP/UDP服務(wù)器 (監(jiān)控系統(tǒng)狀態(tài))

    Linux環(huán)境中實(shí)現(xiàn)并發(fā)TCP/IP服務(wù)器。多線程在解決方案中提供了并發(fā)性。由于并發(fā)性,它允許多個(gè)客戶端同時(shí)連接到服務(wù)器并與服務(wù)器交互。 Linux多線程編程概述 許多應(yīng)用程序同時(shí)處理多項(xiàng)雜務(wù)。服務(wù)器應(yīng)用程序處理并發(fā)客戶端;交互式應(yīng)用程序通常在處理后臺(tái)計(jì)算時(shí)處理用戶

    2024年02月07日
    瀏覽(20)
  • day-08 基于Linux的網(wǎng)絡(luò)編程(套接字和標(biāo)準(zhǔn)I/O、分離I/O流、epoll、多線程服務(wù)器)

    標(biāo)準(zhǔn)I/O函數(shù)(stdio)是在C語(yǔ)言中用于進(jìn)行輸入和輸出操作的庫(kù)函數(shù) 。它們包括了一組標(biāo)準(zhǔn)的輸入和輸出函數(shù),如printf、scanf、fopen、fclose等。標(biāo)準(zhǔn)I/O函數(shù)具有以下優(yōu)點(diǎn): 簡(jiǎn)單易用 :標(biāo)準(zhǔn)I/O函數(shù)提供了簡(jiǎn)潔的接口,使得輸入和輸出操作變得簡(jiǎn)單易用。開發(fā)人員無(wú)需自行處理底層

    2024年02月09日
    瀏覽(91)
  • Linux網(wǎng)絡(luò)編程二(TCP三次握手、四次揮手、TCP滑動(dòng)窗口、MSS、TCP狀態(tài)轉(zhuǎn)換、多進(jìn)程/多線程服務(wù)器實(shí)現(xiàn))

    Linux網(wǎng)絡(luò)編程二(TCP三次握手、四次揮手、TCP滑動(dòng)窗口、MSS、TCP狀態(tài)轉(zhuǎn)換、多進(jìn)程/多線程服務(wù)器實(shí)現(xiàn))

    TCP三次握手 TCP 三次握手 (TCP three-way handshake)是TCP協(xié)議建立可靠連接的過(guò)程,確??蛻舳撕头?wù)器之間可以進(jìn)行可靠的通信。下面是TCP三次握手的詳細(xì)過(guò)程: 假設(shè)客戶端為A,服務(wù)器為B 1 、第一次握手(SYN=1,seq=500) A向B發(fā)送一個(gè)帶有SYN標(biāo)志位的數(shù)據(jù)包,表示A請(qǐng)求建立連接。

    2024年02月06日
    瀏覽(42)
  • Linux高并發(fā)服務(wù)器開發(fā)---筆記1(環(huán)境搭建、系統(tǒng)編程、多進(jìn)程)

    Linux高并發(fā)服務(wù)器開發(fā)---筆記1(環(huán)境搭建、系統(tǒng)編程、多進(jìn)程)

    0613 首先這整個(gè)系列筆記屬于筆記①:牛客校招沖刺集訓(xùn)營(yíng)—C++工程師中的 第四章 筆記。 視頻課鏈接: 視頻1:Linux高并發(fā)服務(wù)器開發(fā)(40h); 視頻2:第4章 項(xiàng)目制作與技能提升(錄播)(26h30min); 視頻課3: 第5章 高頻考點(diǎn)與真題精講(錄播)中的 5.10-5.13 項(xiàng)目回顧 有個(gè)學(xué)

    2024年02月15日
    瀏覽(108)
  • Web服務(wù)器實(shí)現(xiàn)|基于阻塞隊(duì)列線程池的Http服務(wù)器|線程控制|Http協(xié)議

    Web服務(wù)器實(shí)現(xiàn)|基于阻塞隊(duì)列線程池的Http服務(wù)器|線程控制|Http協(xié)議

    代碼地址:WebServer_GitHub_Addr 摘要 本實(shí)驗(yàn)通過(guò)C++語(yǔ)言,實(shí)現(xiàn)了一個(gè)基于阻塞隊(duì)列線程池的多線程Web服務(wù)器。該服務(wù)器支持通過(guò)http協(xié)議發(fā)送報(bào)文,跨主機(jī)抓取服務(wù)器上特定資源。與此同時(shí),該Web服務(wù)器后臺(tái)通過(guò)C++語(yǔ)言,通過(guò)原生系統(tǒng)線程調(diào)用 pthread.h ,實(shí)現(xiàn)了一個(gè) 基于阻塞隊(duì)列

    2024年02月07日
    瀏覽(20)
  • Linux網(wǎng)絡(luò)編程二(TCP圖解三次握手及四次揮手、TCP滑動(dòng)窗口、MSS、TCP狀態(tài)轉(zhuǎn)換、多進(jìn)程/多線程服務(wù)器實(shí)現(xiàn))

    Linux網(wǎng)絡(luò)編程二(TCP圖解三次握手及四次揮手、TCP滑動(dòng)窗口、MSS、TCP狀態(tài)轉(zhuǎn)換、多進(jìn)程/多線程服務(wù)器實(shí)現(xiàn))

    1、TCP三次握手 TCP 三次握手 (TCP three-way handshake)是 TCP協(xié)議建立可靠連接 的過(guò)程,確??蛻舳撕头?wù)器之間可以進(jìn)行可靠的通信。下面是TCP三次握手的 詳細(xì)過(guò)程 : 假設(shè)客戶端為A,服務(wù)器為B。 (1) 第一次握手 第一次握手(SYN=1,seq=500) A向B發(fā)送一個(gè)帶有 SYN 標(biāo)志位的數(shù)據(jù)包,

    2024年04月22日
    瀏覽(37)
  • Linux系統(tǒng)編程,使用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的FTP(服務(wù)器/客戶端)

    Linux系統(tǒng)編程,使用C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的FTP(服務(wù)器/客戶端)

    前言 跟著上官社長(zhǎng) 陳哥花了一個(gè)月的時(shí)間終于把Linux系統(tǒng)編程學(xué)的差不多了,這一個(gè)月真的是頭疼啊,各種bug,調(diào)的真心心累,不過(guò)好在問(wèn)題都解決掉了,在此也感謝一下答疑老師,給我提供了很多的思路,本文章是對(duì)前段時(shí)間學(xué)習(xí)Linux,做一個(gè)小小的總結(jié),才疏學(xué)淺,只學(xué)

    2024年02月12日
    瀏覽(23)
  • Linux系統(tǒng)編程5(線程概念詳解)

    Linux系統(tǒng)編程5(線程概念詳解)

    線程同進(jìn)程一樣都是OS中非常重要的部分,線程的應(yīng)用場(chǎng)景非常的廣泛,試想我們使用的視頻軟件,在網(wǎng)絡(luò)不是很好的情況下,通常會(huì)采取下載的方式,現(xiàn)在你很想立即觀看,又想下載,于是你點(diǎn)擊了下載并且在線觀看。學(xué)過(guò)進(jìn)程的你會(huì)不會(huì)想,視頻軟件運(yùn)行后在OS內(nèi)形成一個(gè)

    2024年02月10日
    瀏覽(19)
  • Java 網(wǎng)絡(luò)編程 —— 創(chuàng)建多線程服務(wù)器

    一個(gè)典型的單線程服務(wù)器示例如下: 服務(wù)端接收到一個(gè)客戶連接,就與客戶進(jìn)行通信,通信完畢后斷開連接,然后接收下一個(gè)客戶連接,假如同時(shí)有多個(gè)客戶連接請(qǐng)求這些客戶就必須排隊(duì)等候。如果長(zhǎng)時(shí)間讓客戶等待,就會(huì)使網(wǎng)站失去信譽(yù),從而降低訪問(wèn)量。 一般用并發(fā)性

    2024年02月02日
    瀏覽(22)
  • Linux系統(tǒng)編程:線程控制

    Linux系統(tǒng)編程:線程控制

    目錄 一.?線程的創(chuàng)建 1.1 pthread_create函數(shù) 1.2?線程id的本質(zhì) 二.?多線程中的異常和程序替換 2.1?多線程程序異常 2.2?多線程中的程序替換 三.?線程等待 四. 線程的終止和分離 4.1?線程函數(shù)return 4.2?線程取消 pthread_cancel 4.3?線程退出 pthread_exit 4.4?線程分離 pthread_detach? 五.?總結(jié)

    2024年02月11日
    瀏覽(20)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包