無(wú)錫做公司網(wǎng)站的網(wǎng)絡(luò)搜索詞排名
🐶博主主頁(yè):@??. 一懷明月??
???🔥專欄系列:線性代數(shù),C初學(xué)者入門訓(xùn)練,題解C,C的使用文章,「初學(xué)」C++,linux
🔥座右銘:“不要等到什么都沒(méi)有了,才下定決心去做”
🚀🚀🚀大家覺不錯(cuò)的話,就懇求大家點(diǎn)點(diǎn)關(guān)注,點(diǎn)點(diǎn)小愛心,指點(diǎn)指點(diǎn)🚀🚀🚀
目錄
線程
線程控制?
pthread_create創(chuàng)建線程
pthread_self
pthread_join
Pthread_exit
pthread_detach
pthread_cancel
系統(tǒng)庫(kù)調(diào)用問(wèn)題
線程的局部存儲(chǔ)
線程
重談一次地址空間-虛擬到物理的過(guò)程
文件系統(tǒng)IO的基本單位大小:4kb
內(nèi)存以4GB為例,就有1048576個(gè)頁(yè)框(4kb)
struct page
{
????int flag;//用于表示該頁(yè)的狀態(tài)和屬性
????//描述一個(gè)page的使用情況
????//頁(yè)框的屬性
}
為了對(duì)所有的頁(yè)框進(jìn)行管理,所以需要一個(gè)struct page pages[1048576]的數(shù)組
線程劃分頁(yè)表的本質(zhì):劃分地址空間
Int a=100
根據(jù)a的虛擬地址,找到a的物理地址,a是一個(gè)整形變量,偏移量就位4
在進(jìn)程視角:虛擬地址本身就是資源!
線程共享進(jìn)程數(shù)據(jù),但也擁有自己的一部分?jǐn)?shù)據(jù):
線程ID 一組寄存器(每個(gè)線程有自己的獨(dú)立上下文數(shù)據(jù)) 棧 errno 信號(hào)屏蔽字 調(diào)度優(yōu)先級(jí)
線程控制?
pthread_create創(chuàng)建線程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg); 這個(gè)函數(shù)的參數(shù)包括:* thread:指向 pthread_t 類型的指針,用于存儲(chǔ)新創(chuàng)建線程的標(biāo)識(shí)符。 * attr:指向 pthread_attr_t 類型的指針,用于設(shè)置新線程的屬性,通??梢栽O(shè)為 NULL 表示使用默認(rèn)屬性。 * start_routine:指向一個(gè)函數(shù)的指針,該函數(shù)定義了新線程要執(zhí)行的任務(wù)。它的簽名為 void* func(void*)。 * arg:傳遞給 start_routine 函數(shù)的參數(shù)。//對(duì)象/結(jié)構(gòu)體
linux下有沒(méi)有真正的線程?
沒(méi)有。只有輕量級(jí)進(jìn)程的概念,所以linux os只會(huì)提供輕量級(jí)進(jìn)程創(chuàng)建的系統(tǒng)調(diào)用,不會(huì)直接提供線程創(chuàng)建接口
所以需要一個(gè)庫(kù)pthread,這個(gè)庫(kù)不屬于c/c++,這個(gè)庫(kù)是操作系統(tǒng)自帶的,編譯時(shí)鏈接我們的庫(kù)
function<void()>?是 C++11 中引入的函數(shù)對(duì)象,它可以用來(lái)表示一個(gè)沒(méi)有參數(shù)且沒(méi)有返回值的函數(shù)。在 C++ 中,函數(shù)對(duì)象是可調(diào)用的實(shí)體,類似于函數(shù)指針,但具有更大的靈活性和功能。
事例
#include <iostream> #include <pthread.h> #include <string> #include <unistd.h> #include <functional> #include <time.h> #include <vector>using namespace std;const int threadnum = 5; using func_t = function<void()>;class threaddata { public: threaddata(const string &name, const uint64_t &time, func_t f): threadname(name), createtime(time), func(f){ }public: string threadname;uint64_t createtime;func_t func;};void print(){ cout << "我是線程執(zhí)行的大任務(wù)的一部分" << endl;}// 新線程 void *ThreadRountine(void *args){ threaddata *td = static_cast<threaddata *>(args); // 安全強(qiáng)轉(zhuǎn)threaddata*類型while (true){ cout << "new thread"<< " thread name:" << td->threadname << " thread time:" << td->createtime << endl;td->func(); sleep(1);//測(cè)試一個(gè)線程異常,整個(gè)進(jìn)程就結(jié)束了 // int a=10; // if(td->threadname=="thread-4") // { // cout<<"觸發(fā)異常"<<endl; // a/=0; // } } }// 如何給新線程傳參,如何創(chuàng)建多線程呢 // 獲取返回值// 主線程 int main(){ vector<pthread_t> pthreads;for (int i = 0; i < threadnum; i++){ char pthreadname[64];snprintf(pthreadname, sizeof(pthreadname), "%s-%lu", "thread", i);pthread_t tid;threaddata *td = new threaddata(pthreadname, (uint64_t)time(nullptr), print);pthread_create(&tid, nullptr, ThreadRountine, td);pthreads.push_back(tid); sleep(1); }while (true){ cout << "main thread" << endl;sleep(3); } return 0;}
pthread_self
在Linux中,
pthread_self
函數(shù)用于獲取當(dāng)前線程的線程ID(pthread_t)。它的聲明如下:
#include <pthread.h>pthread_t pthread_self(void);
調(diào)用
pthread_self
函數(shù)將返回當(dāng)前線程的線程ID,即pthread_t
類型的值。線程ID 是一個(gè)唯一標(biāo)識(shí)符,用于區(qū)分不同的線程。通常情況下,你可以將線程ID存儲(chǔ)在變量中以供后續(xù)使用。線程終止
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è)線程。
線程默認(rèn)要被等待
1.線程退出,沒(méi)有等待,會(huì)導(dǎo)致類似進(jìn)程的僵尸問(wèn)題
2.線程退出時(shí),主線程如何獲取新線程的返回值!
pthread_join
pthread_join 是 POSIX 線程庫(kù)中的函數(shù),用于等待指定的線程結(jié)束執(zhí)行。它會(huì)阻塞當(dāng)前線程,直到指定的線程完成為止。
int pthread_join(pthread_t thread, void **retval); * thread:要等待的線程的線程 ID。 * retval:指向指針的指針,用于接收被等待線程的返回值(如果有)。
事例
#include <stdio.h> #include <pthread.h> void* threadFunction(void* arg) {printf("Inside the new thread\n");return (void*)42; } int main() {pthread_t thread;pthread_create(&thread, NULL, threadFunction, NULL); // 創(chuàng)建一個(gè)新線程// 等待新線程結(jié)束void* result;pthread_join(thread, &result);printf("New thread returned: %ld\n", (long)result);return 0; } 在這個(gè)示例中,我們創(chuàng)建了一個(gè)新線程,并在主線程中調(diào)用 pthread_join 來(lái)等待新線程結(jié)束。pthread_join 函數(shù)會(huì)將主線程阻塞直到新線程執(zhí)行結(jié)束, 并且可以獲取新線程的返回值。
需要注意的是,pthread_join 函數(shù)會(huì)阻塞當(dāng)前線程,直到指定的線程結(jié)束。因此,在實(shí)際使用中,需要確保調(diào)用 pthread_join 的線程不是主要的執(zhí)行線程,否則可能會(huì)導(dǎo)致整個(gè)程序被阻塞。
Pthread_exit
pthread_exit函數(shù)用于終止調(diào)用它的線程。當(dāng)線程調(diào)用pthread_exit時(shí),它會(huì)立即退出,而不會(huì)影響其他線程的執(zhí)行。線程在退出時(shí)可以返回一個(gè)指向線程退出狀態(tài)的指針。
例:
pthread_exit((void*)"thread_1 done");
如果線程退出出現(xiàn)異常呢?
如果線程出現(xiàn)異常,整個(gè)進(jìn)程都會(huì)崩潰,所以沒(méi)必要獲取線程退出信號(hào)
線程的返回值,不一定返回的都是字符串,還可以是對(duì)象
線程沒(méi)有非阻塞等待,線程等待很極端,要么一直等,要么不等
線程默認(rèn)是:線程模式j(luò)oinable的(是可以被等待的)
線程是可以被設(shè)置為分離狀態(tài)的
在線程設(shè)置為分離狀態(tài)后,該線程結(jié)束時(shí)系統(tǒng)會(huì)自動(dòng)釋放其所占用的資源,而不需要其他線程調(diào)用pthread_join來(lái)回收資源
pthread_detach
使用 pthread_detach 函數(shù)可以避免出現(xiàn)僵尸線程,提高系統(tǒng)效率。要使用 pthread_detach 函數(shù),首先需要?jiǎng)?chuàng)建線程,并在創(chuàng)建后立即使用 pthread_detach 函數(shù)將線程設(shè)置為分離狀態(tài)。
主線程可以調(diào)用pthread_detach分離新線程
新線程也可以調(diào)用pthread_detach分離自己
pthread_cancel
線程取消
Pthread_cancel(tid);
線程如果是分離的,是可以被取消的,但是不可以被等待
如果線程是被取消的,線程返回的值是-1,
全部都不是系統(tǒng)直接提供的接口,而是原生線程庫(kù)pthread(默認(rèn)是os自帶的)提供的接口
linux中的線程被叫作用戶級(jí)線程
系統(tǒng)庫(kù)調(diào)用問(wèn)題
線程要有獨(dú)立屬性
1)硬件上下文
2)棧:
新線程的棧,在庫(kù)維護(hù)
默認(rèn)地址空間中的棧,由主線程使用
clone 是一個(gè)系統(tǒng)調(diào)用,用于創(chuàng)建一個(gè)新的進(jìn)程或線程。與 fork 系統(tǒng)調(diào)用不同的是,clone 允許創(chuàng)建的新進(jìn)程或線程與父進(jìn)程或線程共享某些資源,如內(nèi)存空間、文件描述符等,從而實(shí)現(xiàn)更靈活的進(jìn)程/線程管理。
clone 的原型如下:
int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);
其中參數(shù)含義如下:
* fn:指向新進(jìn)程/線程執(zhí)行的函數(shù)指針
* child_stack:指向新進(jìn)程/線程棧的指針
* flags:用于指定創(chuàng)建新進(jìn)程/線程的標(biāo)志
* arg:傳遞給新進(jìn)程/線程執(zhí)行函數(shù)的參數(shù)
clone 的常用標(biāo)志包括:
* CLONE_VM:共享內(nèi)存空間
* CLONE_FS:共享文件系統(tǒng)信息
* CLONE_FILES:共享文件描述符
* CLONE_SIGHAND:共享信號(hào)處理器
線程庫(kù)不僅要管理每個(gè)線程tcb,還要提供一些方法(pthread_create/pthread_join,pthread_cancel/pthread_self)
線程的局部存儲(chǔ)
在 C/C++ 中,__thread 是一種線程局部存儲(chǔ)(Thread-Local Storage,TLS)的實(shí)現(xiàn)方式,用于聲明線程私有變量。在使用 __thread 關(guān)鍵字聲明的變量中,每個(gè)線程都會(huì)有自己獨(dú)立的變量副本,不同線程之間互不影響。
__thread int g_val=100;//線程的局部存儲(chǔ)
g_val 被聲明為一個(gè) __thread 變量,其初始值為 100。這意味著每個(gè)線程都會(huì)有一個(gè)名為 g_val 的變量,且其初始值為 100。不同線程中對(duì) g_val 的操作都是互相獨(dú)立的,一個(gè)線程修改 g_val 的值不會(huì)影響到其他線程中 g_val 的值。
線程可以進(jìn)行fork?線程可以進(jìn)行exec*程序替換嗎?
可以fork,就是整個(gè)進(jìn)程創(chuàng)建了一個(gè)子進(jìn)程
程序替換之后,整個(gè)進(jìn)程會(huì)被替換,所以建議,線程直接程序替換
??🌸🌸🌸如果大家還有不懂或者建議都可以發(fā)在評(píng)論區(qū),我們共同探討,共同學(xué)習(xí),共同進(jìn)步。謝謝大家! 🌸🌸🌸???