實驗2 Linux下基本編程
一、實驗目的
1.掌握vim編譯器
2.掌握gcc編譯器的使用
3.瞭解fork()程式
二、實驗工具與裝置
1.實驗裝置:電腦(帶CD-ROM)一台。
三、實驗預備知識
1. vim的編輯器
使用文法:Vim <被編輯的檔案名稱>
Vim有三種模式:命令模式、插入模式、最後行模式。
命令模式:
剛啟動Vim後,就處於該模式。在此模式下,允許用Vim的子命
令來編輯檔案或轉移到其它模式。如:
x命令:刪除游標上面的字元。
方向鍵:移動游標。
i命令:進入插入模式,可在當前游標處插入字元。
a命令:進入插入模式,可在當前游標後插入字元。
R命令:從當前游標處開始替換文本。
r命令:替換當前游標處字元。
~命令:對當前游標處字母進行大小寫轉換。
dd命令:刪除游標所在行。
dw命令:刪除游標所在處字。
h命令:游標左移。
l命令:游標右移。
k命令:游標上移。
j命令:游標下移。
:命令:進入最後一行模式。
插入模式:
此模式下允許輸入文本,用斷行符號鍵換行,Esc 進入命令模式。
最後一行模式:
w命令:將檔案存檔,但不退出。
wq命令:將檔案存檔,並退出。
q! 命令:不儲存檔案並退出。
r命令:將另一個檔案內容插入當前游標處。
2.gcc編譯器
Unix 上使用的C 語言編譯器cc,在Linux上的派生就是gcc。在使用vim編寫完源程
序之後,返回到shell下面,使用gcc對來源程式進行編譯的命令是:
gcc 來源程式
其中,“來源程式”即為你編寫的以.c 為副檔名的C 語言原始碼檔案。
如果原始碼沒有語法錯誤,使用以上命令編譯,會在目前的目錄下產生一個名為a.out
的可執行檔。如果原始碼有語法錯誤,則不會產生任何檔案,gcc編譯器會在shell中
提示你錯誤的地點和類型。
也可以使用以下方法編譯原始碼檔案,產生自命名的可執行檔:
gcc 源檔案–o 自命名的檔案名稱
執行目前的目錄下的編譯產生的可執行檔,使用以下格式:
./可執行檔名
3.fork() 函數說明
pid_t fork(void)
fork()會產生一個新的子進程。該函數包含於標頭檔unistd.h 中。其子進程會複製
父進程的資料與堆棧空間,並繼承父進程的使用者代碼、組代碼、環境變數、已開啟的文
件代碼、工作目錄和資源限制等。Linux 使用copy-on-write(COW)技術,只有當其中一
進程試圖修改欲複製的空間時才會做真正的複製動作,由於這些繼承的資訊是複製而
來,並非指相同的記憶體空間,因此子進程對這些變數的修改和父進程並不會同步。此
外,子進程不會繼承父進程的檔案鎖定和未處理的訊號。注意,Linux不保證子進程會比
父進程先執行或晚執行,因此編寫程式時要留意死結或競爭條件的發生。
傳回值,如果fork()調用成功則在父進程會返回建立立的子進程代碼(PID),而在新
建立的子進程中則返回0。如果fork() 失敗則直接返回-1,失敗原因存於errno中。失
敗的原因有三個:
1) 系統記憶體不夠;
2) 進程表滿(容量一般為200~400);
3) 使用者的子進程太多(一般不超過25個)。
錯誤碼:EAGAIN 記憶體不足;ENOMEM 記憶體不足,無法配置核心所需的資料結構空
間。
四、實驗內容和步驟
實驗一:
在Linux環境下,用c語言編程,使用系統調用fork建立進程多個子進程。
(1)在終端裡輸入vim a.c,啟動vi.
(2)按a或者i進入插入模式,在裡面輸入以下代碼。
#include "stdio.h"
#include "sys/types.h"
#include "unistd.h"
int main()
{
pid_t pid1;
pid_t pid2;
pid1 = fork();
pid2 = fork();
printf("pid1:%d, pid2:%d\n", pid1, pid2);
}
(3)按Esc鍵進入命令模式,輸入:和wq 進行儲存退出vim.
(4)用gcc編譯器編譯該程式: gcc –o a a.c –ggdb
(5)運行剛剛編譯的程式:./a
要求:
A. 請說出執行這個程式後,將一共運行幾個進程。
B. 觀察運行結果,並給出分析與解釋。
這個程式運行後,一共將運行4個進程。這4個進程並沒有嚴格的區分先後順序。
剛開始未執行fork()函數時,父進程的pid1和pid2均為0,執行第一個fork()函數時,複製父進程得到一個子進程f1,f1的pid1和pid2均為0,父進程的pid1=f1的id;
執行第二個fork()函數時,繼續複製父進程得到子進程f2,則父進程的pid1=f1的id,pid2=f2的id,f2的pid1=f1的id,f2的pid2=0;
複製進程f1得到進程f11,則f1的pid1=0,f1的pid2=f11的id,f11的pid1和pid2均為0;
實驗二:
首先分析一下代碼運行時其輸出結果有哪幾種可能性,按照實驗1步驟編譯調試觀察其實際輸出情況,比較兩者的差異,分析其中的原因。
void main (void)
{ int x=5;
if( fork( ) )
{
x+=30;
printf (“%d\n”,x);
}
else
printf(“%d\n”,x);
printf((“%d\n”,x);
}
(寫出可能的實驗結果及其分析說明)
可能的輸出結果:
1.35 5 35 5父進程執行if語句裡的printf然後子進程執行else語句裡的printf,父進程執行最後一個printf,子進程執行最後一個printf
2.5 35 35 5子進程執行else語句裡的printf,父進程執行if語句裡的printf,父進程執行最後一個printf,子進程執行最後一個printf
3.35 5 5 35父進程執行if語句裡的printf然後子進程執行else語句裡的printf,子進程執行最後一個printf,父進程執行最後一個printf
4.5 35 5 35子進程執行if語句裡的printf然後父進程執行else語句裡的printf,父進程執行最後一個printf,子進程執行最後一個printf
5.35 35 5 5父進程執行if語句裡的printf然後父進程執行最後一個printf,子進程執行else語句裡的printf,子進程執行最後一個printf
6.5 5 35 35子進程執行if語句裡的printf然後子進程執行最後一個printf,父進程執行else語句裡的printf,父進程執行最後一個printf
五、實驗總結
1.寫出實驗報告。
2. 利用vim對linux文字檔進行編輯。
3.編寫fork()程式,並利用gcc進行編譯、調試和運行。