中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

老河口做網站免費的外貿b2b網站

老河口做網站,免費的外貿b2b網站,wordpress 完整模板,做網站的一般步驟線程概念 線程這個詞或多或少大家都聽過,今天我們正式的來談一下線程; 在我一開始的概念中線程就是進程的一部分,一個進程中有很多個線程,這個想法基本是正確的,但細節(jié)部分呢我們需要細細講解一下; 什么…

線程概念

線程這個詞或多或少大家都聽過,今天我們正式的來談一下線程;

在我一開始的概念中線程就是進程的一部分,一個進程中有很多個線程,這個想法基本是正確的,但細節(jié)部分呢我們需要細細講解一下;

什么是線程

1.線程是進程執(zhí)行流中的一部分,就是說線程是進程內部的一個控制序列;

2.線程是操作系統(tǒng)調度的基本單位;

3.在linux中沒有真正意義上的線程,也就是操作系統(tǒng)中說的tcb(thread ctrl block),但是其他的操作系統(tǒng)是有的不同的操作系統(tǒng)實現(xiàn)不同(如windows就是在pcb下再次構建了tcb的數(shù)據結構);為什么linux下沒有真正意義的線程呢?因為線程再操作系統(tǒng)中也是需要被管理的,可是線程的管理一定得創(chuàng)建數(shù)據結構,創(chuàng)建復雜的數(shù)據結構一定需要增加維護的成本與難度,而線程的管理其實和進程是相似的;所以聰明的linux程序員將線程管理設計為了輕量化的進程,將線程與進程統(tǒng)一管理,減輕了代碼的復雜度,便于維護提高效率;(線程粒度細于進程

4.線程其實是進程的一部分,所以線程運行的地方就是在進程的虛擬地址空間中的;因為線程本身也是屬于進程的一部分的,只是被加載到了進程隊列中運行而已;(進程就像是一個家庭,線程就像是家庭中的每一個人,每個人都有自己的工作,所以需要分開執(zhí)行,也就是處于進程隊列中),進程會分配的資源給線程(家庭中的資源會分配給每個人,比如爸爸要去遠的地方工作需要開車,那車子這個資源就會分配給父親),這個資源包括代碼和數(shù)據,之前我們理解的進程可以當作是主線程,通過分配自己的代碼給它內部的線程,內部的線程拿到數(shù)據和代碼資源區(qū)執(zhí)行分配給它的工作,從而執(zhí)行相應的操作;

重談虛擬地址空間

頁表如何映射

計算頁表大小

?所以一個頁表最大為4mb,并且一個頁表的二級頁表不一定為1024個,因為頁表的映射也不是一次就完成的,而已頁表的映射使用完之后還會釋放等;所以一個頁表大小不會大于4mb;

就是這樣的頁表完成了我們的映射;那我們的數(shù)據和代碼都是存儲在這個地址空間上的;而函數(shù)就是一個現(xiàn)成的地址,所以我們分配給線程代碼數(shù)據,是不是可以直接將這個函數(shù)分給線程呢?這樣不就等于把線程需要執(zhí)行的工作劃分給了線程嗎?

所以線程劃分資源本質上是將地址空間中的資源進行分配

為什么我們要創(chuàng)建線程?線程優(yōu)點

1.同一進程中線程之間的切換更加輕量化;

在我們的內存中最快的是寄存器,,cpu之間拿寄存器中的數(shù)據進行計算,寄存器也需要獲取數(shù)據,而寄存器不是之間從內存中拿數(shù)據的,因為內存相較于寄存器還是太慢了,所以它們之間還有一個cache緩存,這個cache中存放的是當前進程的數(shù)據和指令,寄存器可以很快的就從cache中拿到一個進程中的數(shù)據(cache命中率會很高,因為都在同一進程,都是熱數(shù)據);因為同一進程中的線程是共享數(shù)據的,所以cache切換時只需要切換task_struct,而進程之前切換所有數(shù)據都需要切換(進程切換了,進程間具有獨立性,cache中的數(shù)據一定都需要被切換,所咦數(shù)據會變冷重新去命中數(shù)據),這樣的切換消耗會大的多;

2.創(chuàng)建和銷毀線程的代價要小很多;因為線程的數(shù)據已經在內存中了,線程只需要從它所在的進程中獲取數(shù)據即可;

3.io密集型程序,通過多線程可以提高很大的效率,在進行io的時候進程可以讓其他線程進行計算等操作,不需要等待io結束再操作;相比單線程的等待要優(yōu)化非常多;

4.計算密集型程序,在單核cpu中多線程沒有什么提升,想法,線程之間的切換還會降低效率;但是在多核cpu中,多線程可以在多個核上進行計算(計算線程數(shù)要小于等于核的數(shù)量),也是大大提高了計算的效率的;

線程缺點:

由于線程之前沒有獨立性,共享進程代碼數(shù)據,代碼的健壯性要低一些,所以需要進行同步于互斥;缺乏訪問控制->健壯性低;相應的調試也會更難;

線程數(shù)據?

每個線程雖然都是進程的一部分,從進程中獲得數(shù)據的,但是線程一定需要包含自己的數(shù)據;

線程自己的數(shù)據:

1.線程對應的上下文數(shù)據(寄存器)

2.線程運行時數(shù)據(獨立的棧空間)

3.線程id

4.信號屏蔽字

5.調度優(yōu)先級

?6.errno

線程操作

上面講解了線程的基本內容,下面我們來對線程進行操作來理解線程;

我們需要先了解這些linux中posix標準中的原生線程庫中的函數(shù);?

線程創(chuàng)建

pthread_create

這個函數(shù)是用來創(chuàng)建子線程的;

第一個參數(shù)是一個輸出型參數(shù),用來輸出創(chuàng)建線程的tid;

第二個參數(shù)是用來設置線程的屬性的,其實這是一個指向線程屬性對象的指針,通過傳遞我們設置好的對象傳遞給線程從而改變線程的默認屬性,一般我們都傳遞NULL使用默認屬性即可;

第三個參數(shù)是一個回調函數(shù),用來提供給線程運行的代碼,可以理解為讓線程執(zhí)行此函數(shù);

第四個參數(shù)就是一個傳遞給函數(shù)(第三個參數(shù)——回調函數(shù))的參數(shù),這個參數(shù)既可以是普通的內置類型,也可以是結構體,這樣可以很多的數(shù)據;

返回值返回0為成功創(chuàng)建,創(chuàng)建失敗返回返回錯誤碼,不設置errno;

?下面可以看到我們的代碼成功運行了;

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
using namespace std;void *routine(void *data)
{for (int i = 0; i < 5; i++){usleep(100000);cout << "線程1, pid: " << getpid() << endl;}return nullptr;
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, routine, nullptr);for (int i = 0; i < 7; i++){usleep(200000);cout << "線程0, pid: " << getpid() << endl;}return 0;
}

?從上面的現(xiàn)象我們可以清楚的知道線程是一個獨立的執(zhí)行流雖然routine函數(shù)和main函數(shù)它們兩個再同一個程序中且是兩個循環(huán)但是,這兩個循環(huán)同時跑起來了,所以證明了線程的獨立性;

編譯時需要加-lpthread選項

在linux中使用原生線程庫進行編程時我們編譯選項總是需要帶上-lpthread,這個選項在我們前面學習動靜態(tài)庫的時候就很熟悉了,用來連接指定的庫;而似乎我們在以往的編程中除開我們自己創(chuàng)建動靜態(tài)庫的情況之外,我們從未出現(xiàn)過主動連接動靜態(tài)庫的情況;

為什么我們不需要主動去連接呢?這是因為編譯器自動去幫我們連接了,我們的c,c++語言級別的庫也好,linux的系統(tǒng)庫也罷,它們庫的路徑都是已經存儲在編譯器的配置文件中的,編譯器可以自動的找到庫(第一步),然后編譯器會自動連接這些庫(第二步);為什么會自動連接呢?我們可以認為這些系統(tǒng)庫和標準庫是編譯器自己的庫,所以編譯器會自動的連接;而pthread這個庫是posix標準中的原生線程庫;它是屬于第三方庫的,而第三方庫即使它被放到系統(tǒng),標準庫的路徑之下,它也是不會被自動連接的;所以我們需要帶上-lpthread選項去主動連接這個庫;

查看線程

我們看到的線程的現(xiàn)象接下來,我們從系統(tǒng)的角度的入手,使用系統(tǒng)的指令來查看我們的線程的體現(xiàn);

ps -aL

lwp的全稱是light weight process輕量級進程;?

線程的等待與tid獲取函數(shù)

pthread_join

子進程被創(chuàng)建,父進程需要等待進程返回,而線程被創(chuàng)建也需要被等待,但是這里只有主線程和其他線程的區(qū)別,主線程需要等待其他所有線程,防止內存泄漏的問題;

?這里的第一個參數(shù)是指向被等待線程的tid;

第二個參數(shù)是一個輸出型參數(shù)可以用來接收線程的返回值,這個返回值可以是任意類型的數(shù)據(自定義類型也可以);

返回值為0代表等待成功,非0則返回錯誤值,不設置errno碼;

pthread_self

可以獲得線程的tid;

這是一個無參函數(shù)和getpid的使用方式是一樣的;

代碼實現(xiàn)?

?知道了這些基本的函數(shù)后,我們下面用代碼實踐來展示現(xiàn)象并解釋:

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
using namespace std;struct thread_data
{string threadName;string threadReturn;
};void *routine(void *data)
{thread_data *d1 = static_cast<thread_data *>(data);// thread_data *d1 = (thread_data *)(data);int count = 3;for (int i = 0; i < count; i++){printf("tid: %p threadName: %s count: %d\n", pthread_self(), d1->threadName.c_str(), i);sleep(1);}// int a=5/0;//除0錯誤 這里說明了當進程中的某個線程出現(xiàn)異常時,整個進程都會退出// exit(0);//使用exit退出 這里也說明了使用exit會退出整個進程d1->threadReturn="return_"+d1->threadName;return d1;
}void initThread(thread_data *data, int num)
{data->threadName = "thread_" + to_string(num);
}int main()
{pthread_t tid;thread_data *data = new thread_data;initThread(data, 1);int ret_create = pthread_create(&tid, nullptr, routine, (void *)data);void *ret_thread;printf("我是主線程tid: %p\n",pthread_self());pthread_join(tid, &ret_thread);cout << ((thread_data *)ret_thread)->threadReturn << endl;//證明獲得了一個類返回值delete data;return 0;
}

?使用return正常退出的情況:

下面是使用exit和異常退出的情況:?

?

通過代碼和現(xiàn)象我們可以知道這些細節(jié):

1. 我們可以使用join獲取線程的返回值,線程返回值可以為任意類型的指針,所以可以傳遞任意值;

2.我們的子線程退出的時候不能使用exit退出這樣會導致整個進程都退出,我們可以使用return,pthread_exit(后面講),使用cacel取消joined(后面講),這3種方式退出;

3.進程中的任意一個線程出現(xiàn)異常整個進程都會退出

4.線程的tid是一個地址,這個地址是進程堆棧之間的內存區(qū)域(通過上面的現(xiàn)象也可清楚的明白)

由此我們可以知道這些函數(shù)的大致使用;

線程結構體位置

上面我們通過概念與實現(xiàn)基本的了解了線程,接下來我們通過圖像來了解線程的結構體:

其實我們的線程是這樣存在在我們的進程中的,因為linux程序員為了減輕代碼的維護效率linux中沒有真正的線程,而是將線程作為輕量級進程,而用來描述輕量級進程的結構體是存儲在用戶層的,存儲的位置就是共享區(qū)的原生線程庫,線程庫中維護了線程的屬性數(shù)據,內核的執(zhí)行流(tcb控制塊)通過找到進程中的線程庫中的線程結構體從而找到線程代碼執(zhí)行線程;?

所以線程的屬性是由線程庫來維護的,而tid之所以是共享區(qū)之中的代碼的原因就是因為tid指的是共享區(qū)中線程庫中的某個線程結構體所在的首地址;

線程空間的特點

1.線程之間的??臻g是獨立的;

這一點非常好理解,因為函數(shù)在被調用的時候就會創(chuàng)建自己的棧幀嘛;而線程執(zhí)行其實就是執(zhí)行了分給他的函數(shù);所以線程??臻g是獨立的;

2.線程之間是沒有秘密的;

為什么線程之間獨立但是又沒有秘密呢?因為線程總是在一個進程中的嘛,棧之間的數(shù)據,只需要通過一個指針就可以獲得了;

代碼示例:

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <vector>
#include <string>
using namespace std;struct threadData
{string threadName;threadData(int num){threadName = "thread" + to_string(num);}threadData() = default;
};int *g_index;void *routine(void *args)
{int val = 0;threadData *data = (threadData *)args;for (int i = 1; i <=3 ; i++){printf("%s tid: %p val: %d\n", data->threadName.c_str(), pthread_self(), val);val++;}if(data->threadName=="thread1"){val=10000;g_index=&val;sleep(5);}return (void *)0;
}int main()
{vector<pthread_t> tids;for (int i = 0; i < 3; i++){pthread_t tid;threadData *td = new threadData(i);pthread_create(&tid, nullptr, routine, td);tids.push_back(tid);sleep(1);}cout<<"這是thread2的val值: "<<*g_index<<endl;for(auto t:tids){void *retData;pthread_join(t,&retData);}return 0;
}

但是如果我們想要獲得某個??臻g的數(shù)據時這也是可以輕松做到的:

我們在routine函數(shù)中加入一段這樣的代碼,并在main函數(shù)中讀取數(shù)據;

  routine函數(shù)中:if(data->threadName=="thread1"){val=10000;g_index=&val;sleep(5);}
main函數(shù)中:cout<<"這是thread2的val值: "<<*g_index<<endl;

?

線程的變量:__thread選項?

int *g_index;
//int g_val;
__thread int g_val;void *routine(void *args)
{int val = 0;threadData *data = (threadData *)args;for (int i = 1; i <=3 ; i++){//printf("%s tid: %p val: %d\n", data->threadName.c_str(), pthread_self(), val);//val++;printf("%s g_val: %d\n",data->threadName.c_str(),g_val);g_val++;}// if(data->threadName=="thread1")// {//     val=10000;//     g_index=&val;//     sleep(5);// }return (void *)0;
}int main()
{vector<pthread_t> tids;for (int i = 0; i < 3; i++){pthread_t tid;threadData *td = new threadData(i);pthread_create(&tid, nullptr, routine, td);tids.push_back(tid);sleep(1);}//cout<<"這是thread2的val值: "<<*g_index<<endl;for(auto t:tids){void *retData;pthread_join(t,&retData);}return 0;
}

我們線程在使用 g_val全局變量時:

g_val帶上__thread編譯選項時:

?

__thread是編譯選擇,不是c,c++的語法是編譯器的選項;

特點:

?1.將進程全局數(shù)據變?yōu)榫€程全局數(shù)據

2.只能給內置類型帶上這個選項

C++線程庫說明

在我們的C++中是有語言級別的線程庫的(C語言沒有),C++中的線程庫是跨平臺的,但是我們在使用C++線程庫時,我們還是會發(fā)現(xiàn),我們需要帶上編譯選項-lpthread所以說明C++的線程庫是封裝了原生線程庫的,而原生線程庫在linux中是posix標準的,在windows中又有不同的標準;但是C++的線程庫是跨平臺的,所以說明C++的線程庫不僅封裝了linux的posix標準線程庫還封裝了windows下的線程庫;

clone系統(tǒng)調用的封裝

我們前面說線程是輕量級的進程,為什么這么說呢?其實我們在創(chuàng)建線程時使用的pthread_create函數(shù)和創(chuàng)建子進程的fork函數(shù)都是封裝了clone的系統(tǒng)調用;

int clone(int (*fn)(void *), void *child_stack
, int flags, void *arg
, ... /* pid_t *ptid, void *tls, pid_t *ctid */);

這個系統(tǒng)系統(tǒng)調用會指定一片??臻g給新開辟的線程,我們不需要懂clone調用的細節(jié),我們只需要知道,linux中其實在底層上線程的接口也是和進程用的一樣的調用,所以它們在內核層面上是處于同一級別的執(zhí)行流的,所以線程被稱為輕量級進程;

小提示:

線程如何使用進程替換的調用會將當前的整個進程替換掉

線程終止

前面我們說了線程的3個正常退出方式;我們下面來詳細的講解一下:

pthread_exit

這個函數(shù)就是和return一樣的作用,返回一個retval給主線程;這里需要注意的是retval最好是堆上的指針,線程終止棧幀也會銷毀,會導致棧上的數(shù)據被釋放,所以返回值一定要是不被釋放的數(shù)據;

pthread_cancel

這是一個線程終止函數(shù),我們可以通過此函數(shù)終止掉tid的線程:

這里終止了就不需要再join了,如果join了會發(fā)返回非0值;?

這是gpt給出的提示:

盡管?pthread_cancel?函數(shù)可以請求取消另一個線程,但是線程是否真正被取消,以及何時被取消,是由目標線程自身來決定的。目標線程可以選擇忽略取消請求,或者在適當?shù)臅r機響應取消請求并執(zhí)行清理操作。

?線程分離

pthread_detach

我們的主線程永遠是最后退出的,因為需要等待所有創(chuàng)建進程退出,我們常見的服務器一般都是死循環(huán)不退出的程序;而當主線程不關系創(chuàng)建的線程的結果時,可以使用detach來斷開創(chuàng)建線程與主線程之間的關系;,主線程就不需要等待子線程了;

#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include<cstring>
using namespace std;void* routine(void*args)
{cout<<"我是被創(chuàng)建線程"<<endl;
}int main()
{pthread_t tid;pthread_create(&tid,nullptr,routine,nullptr);void* ret;pthread_detach(tid);int ret_join=pthread_join(tid,&ret);printf("%s\n",strerror(ret_join));return 0;
}

當沒有detach時:

當創(chuàng)建的線程被detach時

?所以說明線程不能被同時detach和join;

此外線程可以自己detach自己;

以上就是線程的控制與基本概念,線程部分未完待續(xù);?

http://www.risenshineclean.com/news/37957.html

相關文章:

  • 單位網站建設工作功勞網絡營銷策劃書包括哪些內容
  • 湖南城鄉(xiāng)建設網站全網絡品牌推廣
  • 怎么給公司建網站河南網站建設定制
  • 商城網站搜狗優(yōu)化排名
  • wordpress頁面的評論功能嘉興網站建設方案優(yōu)化
  • 有了網站源碼怎么做網站武漢百度推廣多少錢
  • 自己搭建網站的步驟seo搜索引擎優(yōu)化實訓總結
  • 基于ipv6的網站開發(fā)鄭州百度推廣開戶
  • 網站服務器搭建的步驟采集站seo課程
  • 海南網站建設服務外貿谷歌seo
  • 萊蕪在線沙總寧波seo在線優(yōu)化方案
  • 鄭州英文網站建設刷排名seo
  • 網站建設與管理教學計劃長沙網站se0推廣優(yōu)化公司
  • 如何用電腦做網站服務器網站正能量免費推廣軟件
  • b2c電子商務網站制作商旅平臺app下載
  • 愛淘寶淘寶網首頁seo關鍵詞排名優(yōu)化技巧
  • 揭陽城鄉(xiāng)建設局網站seo網站關鍵詞優(yōu)化工具
  • 網上書店網站建設設計的收獲惡意點擊競價是用的什么軟件
  • 世界頂級網站設計谷歌chrome
  • 北京做網站公司北京seo優(yōu)化方案
  • 重慶物流公司網站建設網站建設企業(yè)建站
  • 創(chuàng)建個人網站多少錢外包推廣服務
  • 網站推廣和宣傳的方法推廣策略有哪些方法
  • 互聯(lián)網軟件外包網站怎么優(yōu)化排名靠前
  • 工商局網站如何做網登2022十大網絡營銷案例
  • php小程序商城青島谷歌優(yōu)化
  • 上海網站建設公司價格深圳網站seo服務
  • 已有網站開發(fā)app終端愛站工具網
  • 做資料網站是自己建服務器好還是租用好網絡營銷活動策劃方案模板
  • 廣東室內設計公司排名內江seo