1. 程式人生 >實用技巧 >其它 >process-thread

process-thread


一、程序的概念:
執行一個程式所分配的資源的總稱,程序是程式的一次執行過程動態的,包括建立、排程、執行和消亡
程式就是我們寫好的程式碼,編譯成可執行檔案後成為程式,存放在硬盤裡面。

但是,當我們點選./a,out去執行的時候,它執行起來:把硬碟程式資料讀到記憶體中,佔用的cpu資源。等等執行所要的資源的總稱,稱為程序。
PCB:程序控制塊
我們的程序是由一個一個程序連結串列的來管理的,這個表叫程序控制塊PCB,裡面有程序標識pid,程序使用者,程序狀態,,優先順序檔案描述符表的資訊。通過唯一標識pid號進行管理,這個pid其實和fd檔案描述符的用法類似,就是一個結構體下標。

一個程序有四種狀態:執行態(正常就是執行態) ,等待態(休眠),停止態()程序被命令中止,殭屍態(程序已經被中止,但是pcb資源沒有被回收)

程序建立

#include  <unistd.h>
 pid_t  fork(void);
建立新的程序,失敗時返回-1
成功時父程序返回子程序的程序號,子程序返回0
通過fork的返回值區分父程序和子程序

子程序繼承了父程序的內容
父子程序有獨立的地址空間,互不影響
若父程序先結束
子程序成為孤兒程序,被init程序收養
子程序變成後臺程序
若子程序先結束
父程序如果沒有及時回收,子程序變成殭屍程序

程序回收:
子程序結束時由父程序回收
孤兒程序由init程序回收
若沒有及時回收會出現殭屍程序

回收全部子程序
 #include  <unistd.h>
 pid_t wait(int *status); 
 成功時返回回收的子程序的程序號;失敗時返回EOF
 若子程序沒有結束,父程序一直阻塞
 若有多個子程序,哪個先結束就先回收
 status 指定儲存子程序返回值和結束方式的地址
 status為NULL表示直接釋放子程序PCB,不接收返回值
 回收指定程序:
 #include  <unistd.h>
  pid_t waitpid(pid_t pid, int *status, int option);
   
 成功時返回回收的子程序的pid或0;失敗時返回EOF
  pid可用於指定回收哪個子程序或任意子程序
 status指定用於儲存子程序返回值和結束方式的地址
 option指定回收方式,0 或 WNOHANG

二、執行緒的概念;
由於程序間通訊資料互動非常麻煩且程序開銷非常大。所以我們引入了執行緒的概念。執行緒是輕量級的程序:
linux其實不區分程序和執行緒:他們都是一個task_struct連結串列來管理。
程序右不同的pid號,同一程序下所有執行緒都共享同一個pid。並且就算你不建立執行緒,那麼程序裡面也會有一個執行緒。就是你一個./a.out這個程序,執行mian函式即是一個程序也是一個執行緒。多執行緒下的task_structlm裡面的pid號是一樣的。

執行緒的好處:
大大提高了任務切換的效率
避免了額外的TLB & cache的重新整理

執行緒的建立:

#include  <pthread.h>
 int  pthread_create(pthread_t *thread, const
       pthread_attr_t *attr, void *(*routine)(void *), void *arg);

 成功返回0,失敗時返回錯誤碼
 thread 執行緒物件
 attr 執行緒屬性,NULL代表預設屬性
 routine 執行緒執行的函式
 arg 傳遞給routine的引數 ,引數是void * ,注意傳遞引數格式,

pthread_t  pthread_self(void)   檢視自己的TID

建立一個執行緒去處理 void *(*routine)(void *)這個函式,處理完畢,執行緒結束並登出。如果程序結束,那麼所有的執行緒都結束,不管你的程式有沒有執行完。一個執行緒用exit();退出,所有的執行緒都會退出。exit()直接退出程式。

執行緒的回收:

#include  <pthread.h>
 int  pthread_join(pthread_t thread, void **retval);
       
 成功返回0,失敗時返回錯誤碼
 thread 要回收的執行緒物件
 呼叫執行緒阻塞直到thread結束
 *retval 接收執行緒thread的返回值

執行緒的取消:

int pthread_cancel(pthread_t thread);

取消是停止執行緒但是資源沒有釋放
執行緒的結束:

 #include  <pthread.h>
 void  pthread_exit(void *retval);
       
 結束當前執行緒
 retval可被其他執行緒通過pthread_join獲取
 執行緒私有資源被釋放

——————————————————————————————————————————————
三、執行緒間的同步和互斥
執行緒間的同步:
訊號量
適用於,當某事件發生後,另一個事件才能發生的情況:例如:
我一個執行緒要往一個buf裡面寫資料,我另一個執行緒要讀資料。
肯定要先寫才能讀資料啊,所以我可以定義一個訊號量,起始訊號量為0 ,用於訊號的同步,當我寫好之後我的訊號量+1,這樣就可以讀資料了。讀完訊號量減一。這樣就不能再次讀資料了。

訊號量操作:

1)初始化訊號量:
 #include  <semaphore.h>
 int  sem_init(sem_t *sem, int pshared, unsigned int val);
 成功時返回0,失敗時EOF
 sem  指向要初始化的訊號量物件
 pshared   0 – 執行緒間   1 – 程序間
 val  訊號量初值

2)訊號量的P/V操作:
 #include  <semaphore.h>
 int  sem_wait(sem_t  *sem);       P操作
 int  sem_post(sem_t  *sem);       V操作
 成功時返回0,失敗時返回EOF
 sem  指向要操作的訊號量物件

執行緒間的互斥:
鎖機制:mutex
適用於:多執行緒訪問共享資源時,對共享資源上鎖。讓其它執行緒不可訪問。以避免出現數據紊亂的情況。

比如我一個執行緒在往一個buf裡面寫資料
我另一個也在往buf裡面寫資料
因為執行緒是並行的,這樣這個資料你永遠都預測不到它長什麼樣子了
一個執行緒申請鎖後必須釋放鎖。
要不然共享資源就變成你家的資源了,別人都用不了。

初始化鎖:
#include  <pthread.h>
 int  pthread_mutex_init(pthread_mutex_t *mutex,
       const pthread_mutexattr_t *  attr);
 成功時返回0,失敗時返回錯誤碼
 mutex  指向要初始化的互斥鎖物件
 attr  互斥鎖屬性,NULL表示預設屬性

2)申請鎖
#include  <pthread.h>
 int  pthread_mutex_unlock(pthread_mutex_t *mutex);

 成功時返回0,失敗時返回錯誤碼
 mutex  指向要初始化的互斥鎖物件
 執行完臨界區要及時釋放鎖

3)釋放鎖
#include  <pthread.h>
 int  pthread_mutex_unlock(pthread_mutex_t *mutex);

 成功時返回0,失敗時返回錯誤碼
 mutex  指向要初始化的互斥鎖物件
 執行完臨界區要及時釋放鎖

——————————————————————————————————
多程序與多執行緒的比較:

程序:
程序有獨立的地址空間
Linux為每個程序建立task_struct
每個程序都參與核心排程,互不影響

執行緒:
程序在切換時系統開銷大
很多作業系統引入了輕量級程序LWP
同一程序中的執行緒共享相同地址空間
Linux不區分程序、執行緒

多執行緒共享的資源:
一個程序中的多個執行緒共享以下資源:
可執行的指令
靜態資料
程序中開啟的檔案描述符
當前工作目錄
使用者ID
使用者組ID

執行緒間私有的資源:
每個執行緒私有的資源包括:
執行緒ID (TID)
PC(程式計數器)和相關暫存器
堆疊
錯誤號 (errno)
優先順序
執行狀態和屬性

什麼時候適用多程序,什麼時候使用多執行緒:

1、首先你得理解多程序的怎麼執行的?它是怎麼做到多執行緒並行的。
這個問題其實,多執行緒是假的並行,根據時間片,一會執行這個執行緒,一會執行另一個執行緒。其實他是一個時間處理一條語句,然後時間片輪轉著去執行各執行緒的語句。這比較費時間。
類似於:單核的多程序
時間片輪詢程序排程演算法,它的思想簡單介紹如下: 在作業系統的管理下,所有正在執行的程序輪流使用CPU,每個程序允許佔用CPU的時間非常短(比如10毫秒),這樣使用者根本感覺不出來CPU是在輪流為多個程序服務,就好象所有的程序都在不間斷地執行一樣。但實際上在任何一個時間內有且僅有一個程序佔有CPU及CPU的運算器。

2多程序的實現:
要是你的程序數小於cpu的核數。比如我exynos4412這個板子是4核的,買手機的時候會看的引數就是什麼四核,八核。就是cpu的個數。要是你的程序數小於cpu的核數。那麼你的程序就可以做到真正的併發。就是在同一時間片下,會有1,2,3,4等程序同時執行程式的可能。要是程序數大於ccpu核數,那麼也將採用 ——時間片輪詢程序排程演算法。不過有四各時間片可以排程。

結合上面的多程序多執行緒的實現,以及執行緒核程序的特性:

如果你想要少消耗資源:多執行緒

如果你兩個程式要頻繁互動資料:多執行緒

如果你想要兩程式間資料少互動為了安全:多程序

如果你想要程式跑的快:多程序

選擇多程序核多執行緒要更據實際來選。

比如我做到安防監控的item。我絕對一個選多程序核多執行緒一起用:

我資料有上行把zigbee的資料交給web。資料下行有web傳送命令到硬體實現控制。
那麼這上行,和下行完全不用資料互動,而且我的開發板有足夠多的空間,而且總共的程序有:cgi 上下行。好像才三個。不過好像還有boa,那這樣也才4個程序。我開發板是4核的牛逼。所以在總的A9框架上我選擇fork多程序。
然後我資料採集程序要採集很多一個的資料,這時候我就採用多執行緒。nice————