C 四) 執行緒與程序

2022-03-17 21:30:11 字數 3161 閱讀 2642

c98標準中不支援執行緒建立,c11標準中才有執行緒建立支援。

目前windows和linux系統都自帶建立程序和執行緒函式,程序process,執行緒thread。

1、程序與執行緒

比如我們一樓有個圖書櫃,那這個圖書櫃的存在就相當於資料已經載入到記憶體中了,你在那邊讀計算機系統書,然後我過來拿起一本資料結構書讀。對於這個整體,你和我是兩個執行緒,圖書櫃+你+我是這個程序。如果你我讀同一本書就比較麻煩了,就是多執行緒程式設計的問題了,兩個執行緒讀同一記憶體資料想想有啥辦法不?

圖1 程式記憶體痕跡

2、程序與執行緒的區別

作業系統會以程序為單位,分配系統資源(cpu時間片、記憶體等資源),程序是資源分配的最小單位。執行緒,有時被稱為輕量級程序(lightweight process,lwp),是作業系統排程(cpu排程)執行的最小單位。即程序是作業系統資源分配的基本單位,而執行緒是處理器任務排程和執行的基本單位;執行緒是程序的一部分。

打個比方:程序是火車,那執行緒就是其中的車廂。那這個火車有10節車廂,就相當於這個程序有10個執行緒。如果在同一時間從上海到太原的列車有5趟,就是5倆火車同時開,那就是有5個程序。相比而言,加一趟列車難,加一節車廂容易。如果一節車廂壞了,處理不好會影響這輛火車;但是一趟並行的火車壞了,並不會影響其他趟火車。車廂之間可以相互走動,但各趟火車之間沒法走動。

通過火車例子可以看出,同乙個程序內的多個執行緒之間資料可以分享,各個程序之間的資料是隔離的,跨程序資料互動需要通過程序間通訊機制等外力才行;建立程序或撤消程序時,由於系統都要為之分配和**資源,導致系統的開銷明顯大於建立或撤消執行緒時的開銷,但是程序有獨立的位址空間,乙個程序崩潰後,在保護模式下不會對其它程序產生影響;執行緒有自己的堆疊和區域性變數,但執行緒之間沒有單獨的位址空間,乙個程序死掉就等於所有的執行緒死掉,所以多程序的程式要比多執行緒的程式健壯,但在程序切換時,耗費資源較大,效率要差一些。

所以,在程序與執行緒之間,沒有說哪個是最好的,只有跟據不同的應用場景擇優使用,一般都是多程序多執行緒一起使用。

3、系統介面

建立子程序程序

windows:

createprocess(),引數比較多,可以指定某個可執行程式,不一定是自身程式。

bool createprocess (

lptstr lpcommandline,        

lpsecurity_attributes lpprocessattributes。

lpsecurity_attributes lpthreadattributes,        

bool binherithandles,        

dword dwcreationflags,

lpvoid lpenvironment,        

lpctstr lpcurrentdirectory,        

lpstartupinfo lpstartupinfo,        

lpprocess_information lpprocessinformation 

);

linux:

pid_t fork(void);
返回值大於0表示現在執行的是父程序,等於0表示執行的是子程序,-1表示建立程序失敗。

啟動程序

#include int execl(const

char *path, const

char *arg, ...);

我們後台應用就有這個。假設有個businesscenter和business兩個可執行程式,businesscenter相當於business的控制中心/統一排程程式,那麼可以讓businesscenter程式拉起business程式。具體做法是:在ini配置檔案寫上business所在的路徑、可執行程式名,以及啟動幾個。如果寫了5個,那麼在businesscenter程式中就要fork5個子程序。在子程序中呼叫exec函式,如果失敗了會返回,成功了就不會返回了,直到新程式執行結束。fork會將呼叫程序的所有內容原封不動的拷貝到新產生的子程序中,很耗費資源。所以,作業系統都有做了對應優化。使得fork結束後如果遇到exec函式並不立刻複製父程序的內容,而是到了真正實用的時候才複製。

執行緒windows:

handle createthread(

lpsecurity_attributes lpthreadattributes,

// size_t dwstacksize,//

initialstacksize:新執行緒的初始化棧的大小,可設定為0

lpthread_start_routine lpstartaddress,//

threadfunction:被執行緒執行的**函式,也稱為執行緒函式

lpvoid lpparameter,//

threadargument:傳入執行緒函式的引數,不需傳遞引數時為null

dword dwcreationflags,//

creationoption:控制線程建立的標誌

lpdword lpthreadid//

threadidentifier:傳出引數,用於獲得執行緒id,如果為null則不返回執行緒id

)

linux:

#includeint pthread_create(pthread_t *tidp,const pthread_attr_t *attr,

void *(*start_rtn)(void*),void *arg);

c11:

//

thread example

#include //

std::cout

#include //

std::thread

void

foo()

void bar(int

x)int

main()

4、**編寫難易度

我們寫的**都是順序執行的,有些場景需要並行,那多執行緒的價值就存在了。像我們有個程式,乙個程序裡有兩個執行緒,主線程主要用來是接收其他系統發來的tcp資料;子執行緒是從管道(檔案)中讀取資料,然後做業務邏輯處理。

多執行緒因為可以共享資料,所以多個執行緒對共享資料的那塊記憶體進行寫操作時候,需要加鎖,對鎖處理不好會引起死鎖,忙等待,導致程式的僵死,這塊比較難,所以覺得要比寫多程序複雜。

C 執行緒 第四執行緒例項

場景 系統中常常會有一些需要定時去迴圈執行的儲存過程或方法等,這時就出現了定時任務小程式。模型 查詢需定時執行的計畫任務 插入執行緒池 執行任務 static void mainmethod 查詢計畫任務 static void querytask threadpool.queueuserworki...

四 執行緒管理 NSThread

1 建立新執行緒的三種方式,例如 nsthread thread nsthread alloc initwithtarget self selector selector demo object nil thread start nsthread detachnewthreadselector se...

C 基礎 多執行緒筆記 四 執行緒池

現在到了關於多線最簡單使用的最後一篇筆記。無論從什麼角度來看,每一項事物都應該有其所在的空間,而對於執行緒來說,執行緒池就是它所存在的空間,或者叫容器了。接下來,看看這個執行緒池是如何使用的吧!概念 manualresetevent,通知乙個或多個正在等待的執行緒已發生事件 manualresete...