這里是一部分內容,還會做修改。
一:目的及內容
學習fork(),exec,pthread庫函數的使用,閱讀源碼,分析fork,exec,pthread_create函數的機理
代碼實現:
進程A創建子進程B
子進程B與父進程A分別對應不同的可執行體:A打印Hello world,B實現sum累加
進程B具有三線程,主線程創建新的線程1實現sum累加(從1到參數x),線程2監控輸入參數x
若輸入x是非負整數,線程1開始計算;如果線程1正在計算前次程序,線程2的輸入非負整數和最近一次的又不同,線程1應重新計算;若相同則不需要重新計算
若輸入字母p,則線程1暫停執行。
輸入字母e則線程1打印退出信息后整個進程A和B都退出
若輸入的是其他字符,則線程1打印一個輸入錯誤提示,任務繼續
分析運行中各個執行體的處理器使用,內存使用等基本信息
二 步驟
參考
Linux C編程--fork()詳解 - 張勤一 - CSDN博客
[並發並行]_[pthread]_[對工作線程進行簡單控制-暫停-繼續-停止] - 心如止水 - CSDN博客
Linux多任務編程(三)---exec函數族及其基礎實驗 - 王大壯的博客 - CSDN博客
Linux多線程編程並傳遞多個參數實例 - blankqdb - 博客園
有關pthread線程的暫停與恢復的討論 - 一天 一小步 - CSDN博客
根據題目要求,可知需要兩個執行體A和B。根據模塊化的原則先設計A,再設計B。
1. 審題,根據題目要求,寫了進程A的代碼
#include提供fork(),execlp()函數
#include <sys/wait.h> 提供wait()函數
#include 提供類型pid_t的定義
代碼比較簡單,主要就是創建子進程,子進程用一個新的進程映像替換當前進程映像。

2. 之后寫子進程B的代碼
充分利用模塊化的設計方法。
先是頭文件
#include<pthread.h>提供pthread庫函數
而需要注意,gcc編譯時加上-lpthread,因為pthread並非Linux默認的庫

之后是幾個全局變量,減少線程間傳遞參數的麻煩。

1.主線程
功能是創建2個子線程,線程2監控輸入,線程1打印信息和計算累加。
當線程1,2都退出后主線程退出。
使用pthread_create創建子線程。
使用pthread_join等待線程結束

2.線程2
因為線程2要監控輸入,所以先寫線程2.
線程2第一部分:
主要進行輸入的處理。
詳情見圖片和代碼的注釋。
這里用c++的string處理輸入,因為沒有限制輸入類型

線程2第二部分:
根據輸入確定func值。func作為全局變量調整線程1的工作狀態
同時根據recent和cal判斷是否要重新計算。target是線程1從1開始的累加目標。

線程2第三部分:
根據第二部分得到的func調整線程1工作狀態。
func==2時,利用pthread_join()先等待線程1打印錯誤信息,再退出。
pthread_suspend() pthread_resume()函數是自己定義的函數,用以實現線程1暫停。暫停的實現具體解釋見實驗報告后續部分。

3. 線程1
第一部分:實現線程1的暫停。
利用
pthread_mutex_lock(),pthread_mutexunlock(),pthread_cond_wait(),pthread_cond_broadcast()實現線程的暫停。
源碼體現的暫停實現過程更清晰。



第二部分:線程1進行累加,輸出信息等操作
sleep是為了體現p操作,兩次輸入相同,不同操作而設置。否則可能人輸入的速度不如計算機計算速度,導致第二次輸入還沒到,就得出上一次的結果。

綜上,進程B結構如下
void pthread_suspend(void)
void pthread_resume(coid)
void thread1(void* arg)
void thread2(void*arg)
int main()
三.分析運行中各個執行體的處理器使用,內存使用等基本信息
首先在終端運行進程A。

pgrep 是通過程序的名字來查詢進程的工具,一般是用來判斷程序是否正在運行。在服務器的配置和管理中,這個工具常被應用,簡單明了;
然后打開另一個終端,pgrep -l A查看進程名和pid

pstree -p 26638。以樹狀圖顯示進程,並顯示進程pid。可見父子進程和線程的關系。

ps -T -p 26639 可以查看進程B的線程信息。

使用top查看進程cpu和內存信息。
下圖為示例:

top命令的第三行,cpu狀態:
依次對應:
us:user 用戶空間占用cpu的百分比
sy:system 內核空間占用cpu的百分比
ni:niced 改變過優先級的進程占用cpu的百分比
id:空閑cpu百分比
wa:IO wait IO等待占用cpu的百分比
hi:Hardware IRQ 硬中斷 占用cpu的百分比
si:software 軟中斷 占用cpu的百分比
st:被hypervisor偷去的時間
top命令第四行,內存狀態:
total,free ,used ,buff/cache
依次對應:物理內存總量,空閑內存總量,使用中的內存總量,緩沖內存量
進入top后,交互時,輸入s,系統提示更改刷新間隔。輸入0則不斷刷新。

top -p 26638查看pid為26638的進程(即A)的信息

top -p - H 26639
top命令可以實時顯示各個線程情況。要在top輸出中開啟線程查看,請調用top命令的“-H”選項,該選項會列出所有Linux線程。在top運行時,你也可以通過按“H”鍵將線程查看模式切換為開或關。

四 遇到的問題及解決:
1.編譯時出現c++11標准庫未定義錯誤,因為編譯器使用的庫版本不同。


解決:使用-l鏈接 stdc++

2. gcc編譯時報錯

解決:
在32位模式時,int 和指針類型變量都占32位在64位模式下,int占32位,指針變量占64位

3.如圖

又是-lstdc++解決
五.實驗結果記錄:
執行程序A。程序A 父進程fork 出子進程,之后打印Hello, world!然后執行wait(),等待子進程結束。
子進程調用execlp,執行另一個執行體B。
執行體B中線程2開始監控輸入。
輸入15,是非負整數,之后線程1計算1累加到15.結果為120。120后跟着的15表明計算的是1-15累加。
輸入16,是非負整數,之后線程1計算1累加到16.結果為136。136后跟着的16表明計算的是1-16累加。
輸入18,之后輸入20.線程2監控到由於20與18不同,故線程1不再進行1-18累加,而進行1-20累加。
輸出210.
輸入25,再輸入25.線程2監控到25相同,不需要重新計算,打印信息“輸入相同,不需要重新計算”。線程1計算第一個25,輸出325.
輸入afd。線程2監控,屬於其他字符,線程1打印錯誤信息“input wrong”。
輸入fg。線程2監控,屬於其他字符,線程1打印錯誤信息“input wrong”。
輸入p,線程1暫停執行。打印信息“pause”表明線程1已暫停。
輸入123.線程2檢測到是非負整數,先調用恢復函數解除線程1的暫停。之后打印信息“resume”表示線程1已經恢復。之后線程1執行1-123累加,輸出7626.
輸入e。線程2檢測到要退出。之后線程1打印信息“A and B exited”表示主進程,子進程都要退出。之后主進程和子進程都退出。
結束。
