#include <thread>
#include <iostream>
using namespace std;
void func();
int main(){
thread th = thread(func);
th.join();
cout << "this is my main thread,and thread_id is " << this_thread::get_id() << endl;
}
void func(){
cout << "this is a new thread,and thread_id is " << this_thread::get_id() << endl;
}
(1) 進程與線程區(qū)別霉旗?
進程是并發(fā)執(zhí)行的程序在執(zhí)行過程中分配和管理資源的基本單位澄步,一個動態(tài)概概念,是競爭計算機資源的基本單位目锭。
線程是進程的一個執(zhí)行單元评汰,是進程內(nèi)部調(diào)度實體,是比進程更小的獨立運行的基本單位侣集。線程被稱為輕量級進程键俱。
一個程序至少一個進程,一個進程至少一個線程世分。
每個進程都有自己的進程空間编振,即進程空間,在網(wǎng)絡(luò)和多用戶環(huán)境下臭埋,一個服務(wù)器通常需要接受大量不確定的數(shù)量的用戶的并發(fā)請求踪央,為每一個用戶創(chuàng)建一個進程行不通(進程所需要的資源大),因此操作系統(tǒng)引進線程的概念瓢阴。
線程的執(zhí)行過程是線性的畅蹂,盡管其中會發(fā)生中斷或者暫停,但是該進程資源只為該線性資源服務(wù)荣恐,一旦發(fā)生線程切換液斜,這些資源就會保存起來累贤。
進程分為單線程和多線程,單線程進程宏觀上來說也是線性執(zhí)行過程少漆。多線程宏觀上是線性執(zhí)行臼膏,微觀上是并行。
線程的改變示损,只是cpu的執(zhí)行過程的改變渗磅,而沒有發(fā)生進程所擁有的資源的變化。
(2) 線程比進程具有哪些優(yōu)勢检访?
地址空間:同一進程的線程共享本進程的地址空間始鱼,而進程之外則時獨立的地址空間。
資源擁有:同一進程的線程共享本進程的資源脆贵,不同進程之間的資源獨立医清。
一個進程崩潰后在保護模式下不會對其他進程產(chǎn)生影響,但進程里的一個線程崩掉卖氨,整個進程死去状勤。因此多進程比多線程健壯。
進程的切換所需要的資源大双泪,時間效率低持搜。因此涉及到頻繁的切換使用線程要優(yōu)于進程。同時如果需要同時進行并且共享某些變量的并發(fā)操作焙矛,只能用線程不能用進程葫盼。
執(zhí)行過程:每個獨立的進程都有一個程序運行的入口、順序執(zhí)行序列和程序入口村斟。但是線程不能獨立執(zhí)行贫导,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個線程執(zhí)行控制蟆盹。
線程是處理器調(diào)度的基本單位孩灯,但是進程不是。
兩者均可并發(fā)執(zhí)行逾滥。
優(yōu)缺點:
線程執(zhí)行開銷小峰档,但是不利于資源的管理和保護。線程適合在SMP機器(雙CPU系統(tǒng))上運行寨昙。
進程執(zhí)行開銷大讥巡,但是能夠很好的進行資源管理和保護。進程可以跨機器前移舔哪。
(3) 什么時候用多進程?
對資源的管理和保護要求高欢顷,不限制開銷和效率時,使用多進程捉蚤。
要求效率高抬驴,頻繁切換時炼七,資源的保護管理要求不是很高時,使用多線程布持。
(4) LINUX中進程和線程使用的幾個函數(shù)特石?
進程相關(guān)函數(shù):
(1)獲取進程號:
pid_t getpid(void);
頭文件:sys/types.h、unistd.h 該函數(shù)成功時返回當前ID鳖链,該函數(shù)always successful。
(2)獲取父進程號
pid_t getppid(void)
頭文件sys/types.h墩莫、unistd.h
(3)進程創(chuàng)建
pid_t fork(void)
頭文件:sys/types.h芙委、unistd.h
功能:在當前進程中創(chuàng)建一個進程,與父進程共享代碼段狂秦,復(fù)制父進程的堆棧段和數(shù)據(jù)段灌侣,子進程復(fù)制父進程,然后執(zhí)行fork()后的代碼裂问。向父進程返回創(chuàng)建進程的進程號侧啼,在子進程中返回0。
返回值:fork返回給父進程所創(chuàng)建進程的進程號堪簿,然后返回創(chuàng)建成功標志值為0痊乾,失敗-1或者errno
(4)進程退出
void exit() //value為0代表正常退出,非0(一般1或-1)表示非正常退出椭更,一般會有對應(yīng)情況
父進程:exit(0)和return(0)
子進程:exit(0)
return和exit的區(qū)別是exit停止進程并且value表示進程退出狀態(tài)哪审,return是函數(shù)返回的標志可以返回多種數(shù)據(jù)類型
exit()(庫函數(shù);sdtlib.h)和_exit(系統(tǒng)調(diào)用;unistd.h):終止進程以后虑瀑,_exit()緩沖區(qū)不被保存,exit()緩沖區(qū)被保存
exit函數(shù)作用:進程停止運行之前,檢查文件打開情況虐骑,把文件緩沖區(qū)內(nèi)容寫回文件俱两。,清除其使用的內(nèi)存空間痛侍,并清除其在內(nèi)核中的各種數(shù)據(jù)結(jié)構(gòu)朝氓。
緩沖I/O,對應(yīng)每一個打開的文件主届,在內(nèi)存中都有一片緩沖區(qū)膀篮,每次讀文件,連續(xù)讀出若干條記錄岂膳,這樣在下次讀文件時就可以直接從內(nèi)存緩沖區(qū)讀仁母汀;每次寫文件寫入內(nèi)存緩沖區(qū)谈截,等滿足一定條件筷屡,將緩沖區(qū)內(nèi)容一次性寫入文件涧偷。
僵尸進程:幾乎放棄所有的內(nèi)存空間,沒有任何執(zhí)行代碼毙死,也不能被調(diào)度燎潮,僅僅在進程列表中保留一個位置,記載該進程的退出狀態(tài)供其他進程收集扼倘,除此之外确封,僵尸進程不再占有任何內(nèi)存空間
(5)進程等待函數(shù)
pid_t wait(int *status)
頭文件:sys/type.h;sys/wait.h
功能:掛起調(diào)用他(現(xiàn)在)的進程,直到子進程結(jié)束再菊,然后才接著運行該進程
返回值:成功返回終止的那個進程的id爪喘,失敗返回-1
參數(shù):記錄進程退出的狀態(tài)(正常/異常退出)
pid_t waitpid(pid_t pid ,int *status,int options)
頭文件:sys/type.h;sys/wait.h
參數(shù):pid >0:等待進程ID為pid的子進程
=0:等待同一進程組中的任何子進程
=-1:等待任一子進程,此時和wait一樣
<-1:等待絕對值為pid的進程組的任一子進程
options 0:和wait一樣纠拔,阻塞父進程等待子進程秉剑;WNOHANG:如果pid指定的子進程沒有結(jié)束,則waitpid()函數(shù)立即返回0稠诲,而不是阻塞在這個函數(shù)上等待侦鹏;如果結(jié)束了,則返回該子進程的進程號臀叙。
(6)執(zhí)行進程
int execl(const char*path,const char *arg,....)
所屬庫:unistd.h
函數(shù)功能:運行可執(zhí)行文件
返回值:成功無返回值略水,失敗返回-1或者錯誤信息指針
參數(shù):path:可執(zhí)行文件路徑(如liux的命令路徑,如ls的路徑)劝萤;arg:可執(zhí)行文件(既可以是二進制文件聚请,也可以是Linux下任何可執(zhí)行腳本文件)所需要的參數(shù)
與fork()比較,保留原有進程稳其,執(zhí)行新代碼驶赏。占用原有進程的巢穴,將其代碼段覆蓋
exec族函數(shù):根據(jù)指定的文件名或目錄名找到可執(zhí)行文件既鞠,并用它來取代原調(diào)用進程的數(shù)據(jù)段煤傍、代碼段和堆棧段,在執(zhí)行完之后嘱蛋,原調(diào)用進程的內(nèi)容除了進程號外蚯姆,其他全部被新程序的內(nèi)容替換了。
(7)system
system(調(diào)用/bin/sh來執(zhí)行參數(shù)指定的命令洒敏,file父進程為bash龄恋,即linux的sh命令解析器)
int system(const char *file)
頭文件:stdlib.h
功能:fork+execl,fork建立子進程凶伙,用excel函數(shù)根據(jù)參數(shù)file找到并執(zhí)行可執(zhí)行文件
返回值:對于fork失敗郭毕,system()函數(shù)返回-1。 如果exec執(zhí)行成功函荣,也即command順利執(zhí)行完畢显押,則返回command通過exit或return返回的值.如果exec執(zhí)行失敗扳肛,也即command沒有順利執(zhí)行,比如被信號中斷乘碑,或者command命令根本不存在挖息,system()函數(shù)返回127. 如果command為NULL,則system()函數(shù)返回非0值兽肤,一般為1.
system和execl相比套腹,system不再是當前的進程
用處:a. 當進程認為自己不能再為系統(tǒng)和用戶做出任何貢獻時,就可以調(diào)用任何exec 函數(shù)族讓自己重生资铡。
b. 如果一個進程想執(zhí)行另一個程序电禀,那么它就可以調(diào)用fork函數(shù)新建一個進程,然后調(diào)用任何一個exec函數(shù)使子進程重生害驹。
(8)進程掛起
unsigned int sleep(unsigned int seconds)
頭文件:#include <unistd.h>
函數(shù)說明:sleep()會令目前的進程暫停, 直到達到參數(shù)seconds 所指定的時間, 或是被信號所中斷。sleep結(jié)束后被掛起的進程不一定馬上執(zhí)行蛤育,還是切換到就緒態(tài)等待CPU
返回值:若進程/線程掛起到參數(shù)所指定的時間則返回0宛官,若有信號中斷則返回剩余秒數(shù)。
void usleep(unsigned long usec)//單位為us
由于linux調(diào)度是毫秒級瓦糕,所以usleep不太準
線程相關(guān)函數(shù):
(1)線程創(chuàng)建函數(shù)
#include <pthread.h>
int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg);
pthread_t *restrict tidp, //是一個傳出參數(shù)底洗,用于保存成功創(chuàng)建線程之后對應(yīng)的線程id
const pthread_attr_t *restrict attr, //線程屬性,默認為NULL咕娄,如果想使用具體的屬性也可以修改具體的參數(shù)
void (start_rtn)(void), //指向創(chuàng)建線程所執(zhí)行函數(shù)的入口地址亥揖,函數(shù)執(zhí)行完畢,則線程結(jié)束圣勒。
void *restrict arg); //線程主函數(shù)執(zhí)行期間所使用的參數(shù)
ret-成功返回0 失敗返回錯誤編號费变。注意:由于創(chuàng)建線程函數(shù)是一個庫函數(shù),不是系統(tǒng)調(diào)用函數(shù)圣贸。所以其錯誤信息不能用perror()進行打印挚歧,采用strerror(錯誤號)可以將錯誤信息打印出來。其中strerror函數(shù)是包含#include<string.h>之中的一個庫函數(shù)吁峻。
(2)獲取線程自身ID
#include <pthread.h>
pthread_t pthread_self(void);
ret-調(diào)用線程的線程ID滑负,返回值為一個無符號長整型
說明:線程id是在一個進程中的內(nèi)部標識,但不同進程中的線程id可能相同用含。進程與進程中線程的代碼運行按時間先后順序
(3)比較兩個線程ID
#include <pthread.h>
int pthread_equal(pthread_t tid1, pthread_t tid2);
ret-若相等則返回非0值矮慕,否則返回0值
(4)單個線程退出
#include <pthread.h>
void pthread_exit(void *rval_ptr);//rval_ptr是一個無類型指針,與傳遞給啟動例程的單個參數(shù)類似啄骇,進程中的其他線程可以通過調(diào)用pthread_join函數(shù)訪問到這個指針痴鳄;
返回值:無返回值,跟進程一樣缸夹,線程結(jié)束的時候無法返回到它的調(diào)用者(自身)
(5)等待線程結(jié)束函數(shù)
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);//thread:被等待的線程標識符ID;rval_ptr:一個用戶定義的指針夏跷,它可以用來存儲被等待線程的返回值
ret-成功返回0 否則返回錯誤編號
調(diào)用線程一直阻塞哼转,直到指定的線程調(diào)用pthread_exit,從啟動例程中返回或者被取消槽华;如果線程(指調(diào)用的在等待的pthread)只是從調(diào)用它等待它的例程中返回壹蔓,rval_ptr將包含返回碼;如果線程被取消猫态,由rval_ptr指定的內(nèi)存單元就設(shè)置為PTHREAD_CANCELED.如果線程已經(jīng)處于分離狀態(tài)佣蓉,pthread_t就會調(diào)用失敗,返回EINVAL亲雪。如果對線程的返回值不感興趣勇凭,可以吧rval_prt設(shè)置為NULL。這種情況下义辕,調(diào)用pthread_join將等待線程終止虾标,但不獲取線程的終止狀態(tài)。
分離狀態(tài)說明:在默認情況下線程是非分離狀態(tài)的灌砖,這種情況下璧函,原有的線程等待創(chuàng)建的線程結(jié)束。只有當pthread_join()函數(shù)返回時基显,創(chuàng)建的線程才算終止蘸吓,才能釋放自己占用的系統(tǒng)資源。而分離線程不是這樣子的撩幽,它沒有被其他的線程所等待库继,自己運行結(jié)束了,線程也就終止了窜醉,馬上釋放系統(tǒng)資源宪萄。
說明:這個函數(shù)是一個線程阻塞的函數(shù),調(diào)用它的函數(shù)將一直等待到被等待的線程結(jié)束為止榨惰,當函數(shù)返回時雨膨,被等待線程的資源被收回
(6)線程取消
#include <pthread.h>
int pthread_cancel(pthread_t tid);// thread 要取消線程的標識符ID
ret-成功返回0 失敗返回錯誤碼
功能:取消某個線程的執(zhí)行。調(diào)用了參數(shù)是PTHREAD_CANCELD的pthread_exit函數(shù)读串,但是聊记,線程可以選擇或者忽略、或者立即終止恢暖、或者繼續(xù)運行至Cancelation-point(取消點:會引起阻塞的系 統(tǒng)調(diào)用)排监。函數(shù)并不等待線程終止,它僅僅是提出請求杰捂。線程接收到CANCEL信號的缺省處理(即pthread_create()創(chuàng)建線程的缺省狀態(tài))是繼續(xù)運行至取消點才會退出舆床。
(7)分離釋放線程(由系統(tǒng)回收線程所占資源)
#include <pthread.h>
int pthread_detach(pthread_t thread); // thread 要釋放線程的標識符ID
返回值:若是成功返回0,否則返回錯誤的編號
說 明:linux線程執(zhí)行和windows不同,pthread有兩種狀態(tài)joinable狀態(tài)和unjoinable狀態(tài)。一個線程默認的狀態(tài)是joinable挨队,如果線程是joinable狀態(tài)谷暮,當線程函數(shù)自己返回退出時或pthread_exit時都不會釋放線程所占用堆棧和線程描述符(總計8K多)。只有當你調(diào)用了pthread_join之后這些資源才會被釋放盛垦。若是unjoinable狀態(tài)的線程湿弦,這些資源在線程函數(shù)退出時或pthread_exit時自動會被釋放。unjoinable屬性可以在pthread_create時指定腾夯,或在線程創(chuàng)建后在線程中pthread_detach自己, 如:pthread_detach(pthread_self())颊埃,將狀態(tài)改為unjoinable狀態(tài),確保資源的釋放蝶俱。如果線程狀態(tài)為joinable,需要在之后適時調(diào)用pthread_join班利。
(8)線程清理處理函數(shù)
#include <pthread.h>
void pthread_cleanup_push(void(*rtn)(void*), void *arg);//rtn為清理函數(shù),arg為清理函數(shù)的參數(shù)
void pthread_cleanup_pop(int execute); //調(diào)用刪除上次push的清理程序
當線程執(zhí)行以下動作時調(diào)用清理函數(shù):
a. 調(diào)用pthread_exit;
b. 想用取消請求榨呆;
c. 用非零的execute參數(shù)調(diào)用pthread_cleanup_pop;如果execute=0則函數(shù)不被調(diào)用罗标;
注意正常從線程返回(return)的時候,不會調(diào)用該清理函數(shù)积蜻;
(5) 線程同步闯割?
在Windows下線程同步的方式有:互斥量,信號量浅侨,事件纽谒,關(guān)鍵代碼段
在Linux下線程同步的方式有:互斥鎖证膨,自旋鎖如输,讀寫鎖,屏障(并發(fā)完成同一項任務(wù)時央勒,屏障的作用特別好使) 知道這些鎖之間的區(qū)別不见,使用場景?
互斥鎖:(線程鎖)互斥所保證任何時刻只有一個線程訪問該對象崔步。
自旋鎖:一次只有一個線程進入臨界區(qū)稳吮,其他線程等待(讀寫鎖是自旋鎖的一個特例)
讀寫鎖:多個讀者可以同時讀;寫者必須互斥井濒;寫者優(yōu)于讀者灶似。
屏障:屏障(barrier)是用戶協(xié)調(diào)多個線程并行工作的同步機制。屏障允許每個線程等待瑞你,直到所有的合作線程都達到某一點酪惭,然后從該點繼續(xù)執(zhí)行。目前定義的屏障屬性只有進程共享屬性
進程間的通信方式:1.管道(無名管道)
特點:半雙工者甲、只能用于具有親緣關(guān)系的進程(父子春感、兄弟進程)、可以將它看成一種文件,可以用write和read等函數(shù)對他進行操作鲫懒,但是它不輸于任何文件系統(tǒng)嫩实,并且只存在于內(nèi)存中
2.FIFO (命名管道,它是一種文件類型)
特點:FIFO可以在無關(guān)的進程之間交換數(shù)據(jù)窥岩、FIFO有路徑與之相連甲献,它以一種特殊的文件形式存在于文件系統(tǒng)之中。
FIFO的通信方式類似于在進程中使用文件來傳輸數(shù)據(jù)谦秧,只不過FIFO類型文件同時具有管道的特性竟纳。在數(shù)據(jù)讀出時,F(xiàn)IFO管道中同時清除數(shù)據(jù)疚鲤,并且“先進先出”锥累。
3.消息隊列
消息隊列,是消息的鏈接表集歇,存放在內(nèi)核中桶略。一個消息隊列由一個標識符(即隊列ID)來標識。
特點:消息隊列是面向記錄的诲宇,其中的消息具有特定的格式以及特定的優(yōu)先級际歼、消息隊列獨立于發(fā)送與接收進程。進程終止時姑蓝,消息隊列及其內(nèi)容并不會被刪除鹅心、消息隊列可以實現(xiàn)消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取。
4.共享內(nèi)存(Shared Memory)
指兩個或多個進程共享一個給定的存儲區(qū)纺荧。
特點:共享內(nèi)存是最快的一種 IPC旭愧,因為進程是直接對內(nèi)存進行存取、因為多個進程可以同時操作宙暇,所以需要進行同步输枯、信號量+共享內(nèi)存通常結(jié)合在一起使用,信號量用來同步對共享內(nèi)存的訪問占贫。
5.信號量(semaphore)
特點:信號量用于進程間同步桃熄,若要在進程間傳遞數(shù)據(jù)需要結(jié)合共享內(nèi)存、信號量基于操作系統(tǒng)的 PV 操作型奥,程序?qū)π盘柫康牟僮鞫际窃硬僮魍铡⒚看螌π盘柫康?PV 操作不僅限于對信號量值加 1 或減 1,而且可以加減任意正整數(shù)厢汹、支持信號量組螟深。
匿名管道與命名管道的區(qū)別:
匿名管道是半雙工的,數(shù)據(jù)只能往一個方向流動坑匠。匿名管道只能用于有親緣關(guān)系的進程之間進行通信血崭。
命名管道不同于匿名管道有一個路徑名與之相連,以FIFO的形式存在于文件系統(tǒng)中。
相比于匿名管道夹纫,命名管道有以下特點:
- 既可用于本地咽瓷,又可用于網(wǎng)絡(luò)。
- 可以通過它的名稱而被引用舰讹。
- 支持多客戶機連接茅姜。
- 支持雙向通信。
- 支持異步重疊I/O操作
常見的信號有哪些月匣?
SIGINT钻洒,SIGKILL(不能被捕獲),SIGTERM(可以被捕獲)锄开,SIGSEGV素标,SIGCHLD,SIGALRM