1. 在Linux下實現進度條程序。 通過makefile進行編譯。 建議自主完成一個彩色的進度條。
寫Makefile文件的原因:Makefile文件的作用是命令行編譯鏈接命令nmake使用的文件。它以人本方式規定了make要編譯哪些文件,生成哪些文件,要鏈接哪些文件,生成的.exe文件的名稱等。
思路:
1. 進度條由0%-100%,在字符數組中輸出一串字符時,最后以”\0”結束的,所以需要一個大小為102的數組,加載橙紅的數據用”=”表示。
2. 進度條會出現一個區間,然后在里面進行加載,故先用”[“”]”表示加載的區間。
3. 定義一個rate標識進度。沒進行一次加一,直到100停止
4. 在進行回車前,需要進行刷新
5. 在加載進度時,通過sleep()&usleep()控制睡眠時間,sleep表示秒,usleep表示微妙。
6. 對于加載中旋轉的小圈通過”-|/”順時針進行。
主要代碼如下
#include #include int main() { int rate =0; char str[102]={0}; char * sta=“-\|/”; while(rate《=100) { str[rate]=“-”; printf(“[%-100s],%d%%,[%c]\r”,str,rate,sta[rate%4]); rate++; ffush(stdout); usleep(100000); } retunr 0; }
Linux下程序編寫完成之后,在進行編譯鏈接生成可執行文件
方式1 gcc test.c -o test
。/a.out
方式2 編譯makefile文件
test:test。o gcc -o test -o test.o test.o:test.s gcc -C test.i -o test.o test.s:test.i gcc -S test.i -p test.i test.i:test.c gcc -E test.c -o test.i .PHONY:clean clean: rm -f test.o rm -f test.s rm -f test.i rm -f test 1.回車(\r)和換行(\n)
回車和換行是兩個不同的概念,回車:表示回到當前行的行首。換行:表示光標進入當前行的下一行
在Linux中,\n會進行回車+換行操作,而/r不會進行回車操作,只會被當做控制字符處理。
在Windows下,每行的結尾是《\n》《\r》;在Linux下,每行的結尾是《\n》。所以,Linux下打開Windows的文件,每行會多出一個^M符號;而在Windows下打開Linux文件,所有的內容變成一行。
2.緩沖區
####(1)什么是緩沖區?
緩沖區又稱為緩存,它是內存空間的一部分,在內存空間中預留了一定的存儲空間,這些空間用來緩沖輸入或輸出的書庫,這部分預留的空間就叫做緩沖區。
緩沖區根據其對應的是輸入涉筆還是輸出設備,分為輸入緩沖區和輸出緩沖區。
(2)為什么要引入緩沖區
比如我們從磁盤里取信息,我們先把讀出的數據放在緩沖區,計算機再直接從緩沖區中取數據,等緩沖區的數據取完后再去磁盤中讀取,這樣就可以減少磁盤的讀寫次數,再加上計算機對緩沖區的操作大大快于對磁盤的操作,故應用緩沖區可大大提高計算機的運行速度。
又比如,我們使用打印機打印文檔,由于打印機的打印速度相對較慢,我們先把文檔輸出到打印機相應的緩沖區,打印機再自行逐步打印,這時我們的CPU可以處理別的事情。
現在您基本明白了吧,緩沖區就是一塊內存區,它用在輸入輸出設備和CPU之間,用來緩存數據。它使得低速的輸入輸出設備和高速的CPU能夠協調工作,避免低速的輸入輸出設備占用CPU,解放出CPU,使其能夠高效率工作。
(3)緩沖區的類型
緩沖區 分為三種類型:全緩沖、行緩沖和不帶緩沖。
a、全緩沖
在這種情況下,當填滿標準I/O緩存后才進行實際I/O操作。全緩沖的典型代表是對磁盤文件的讀寫。
b、行緩沖
在這種情況下,當在輸入和輸出中遇到換行符時,執行真正的I/O操作。這時,我們輸入的字符先存放在緩沖區,等按下回車鍵換行時才進行實際的I/O操作。典型代表是鍵盤輸入數據。
c、不帶緩沖
也就是不進行緩沖,標準出錯情況stderr是典型代表,這使得出錯信息可以直接盡快地顯示出來。
(4)緩沖區的刷新 下列情況會引發緩沖區的刷新: 1、緩沖區滿時; 2、執行flush語句; 3、執行endl語句; 4、關閉文件。 可見,緩沖區滿或關閉文件時都會刷新緩沖區,進行真正的I/O操作。另外,在C++中,我們可以使用flush函數來刷新緩沖區(執行I/O操作并清空緩沖區),如:cout《Linux下呢,有一個萬能的“男人”,我們有什么不懂得,就可以去問這個“男人”,它就是man指令。下面我們以查詢fflush()函數的頭文件來使用man命令查詢,輸入man fflush后按回車鍵,就會出現一個查詢文檔。
2.Linux下軟件安裝的幾種方式
rpm安裝的常用選項
操作符 作用
rpm -ivh full_pkgname 安裝
rpm -e pkgame 卸載
rpm -qa[pkgame] 列出所有已經安裝過的包
rpm -ql pkgame 列出一個已經安裝的包安裝了哪些文件
rpm -qf file 列出某個文件由哪幾個包安裝
rpm -qi file 查詢某個安裝包的詳細信息
rpm -nodeps 強制安裝,不用管其他依賴的包
rpm -force 強制安裝,而不管系統中有沒有安裝過這個包
yum安裝
- yum工具是RedHat公司開發的用于管理rpm包的工具
- 使用yum安裝rpm包可以自動解決包之間的依賴關系
- 我們可以自定義yum的源,可以搭建本地yum倉庫
- yum源配置文件為/etc/yum.repos.d/CentOS-Base.repo
操作符 作用
yum install pkg 安裝rpm包
yum remove pkg 卸載rpm包
yum list 從配置文件中指定的yum源列出所有的rpm安裝包
yum search xxx 搜索rpm包
yum groupinstall grp 安裝rpm組件
yum groupremove grp 卸載rpm組件
yum grouplist 列出所有的rpm組件
yum update/yum upgrade 更新所有的rpm包
搭建本地yum庫
1. 將centos安裝盤或安裝鏡像掛載到指定路徑mnt/
2. 備份好配置文件 /etc/yum.repos.d/CentOS-Base.repo到一個指定路徑
3. 刪除配置文件 /etc/yum.repos.d/CentOS-Base.repo
4. 編輯另一個配置文件 /etc/yum.repos.d/CentOS-Media.repo
[local-cdrom] —-》 yum list 時顯示在最右邊的標識;
name=cd —-》 yum 倉庫標識;
baseurl=file:///mnt/ —-》 指定 rpm 倉庫路徑;
gpgcheck=0 —-》 不檢測;
enabled=1 —-》 允許 ;
5. 保存退出
使用yum只下載不安裝rpm包
1. 先安裝一個插件:yum install -y yum-plugin-downloadonly;
2. 對于未安裝過的 rpm 包:yum install -y pkg –downloadonly;
3. 對于已經安裝過的:yum reinstall -y pkg –downloadonly;
4. 指定 rpm 包的下載路徑:yum install -y pkg –downloadonly –downloaddir dir.
源碼安裝
1. 下載源碼包盡量從官網下載,保證安全
2. 源碼包保存路徑約定為:/usr/local/src/
3. 安裝路徑約定為:/usr/local/源碼包名
4. 安裝開始前,先要查看安裝說明 vim INSTALL vim README
5. 查看配置參數:。/configure –help
6. 安裝過程中,每進行完一步要使用echo $? 進行驗證前一步是否產生錯誤
操作符 作用
。/configure –help 查看所有配置參數及含義
。/configure … 配置安裝路徑、安裝模塊
make 編譯
make install 安裝
echo $! 檢查上一步安裝是否出錯,‘0’:正確;‘1’:錯誤
調研task_struct結構體, 理解結構體中的各個字段的含義
Linux內核通過一個被稱為進程描述符的task_struct結構體來管理進程,
task_struct是Linux中的【進程控制塊PCB結構】的具體數據結構
這個結構體包含了一個進程所需的所有信息。它定義在linux-2.6.38.8/include/linux/sched.h文件中。
下面對task_struct這個結構體 進行各個字段的詳細介紹
1. 調度數據成員 (1) volatile long states;
表示進程的當前狀態:
- TASK_RUNNING:正在運行或在就緒隊列run-queue中準備運行的進程,實際參與進程調度。
- TASK_INTERRUPTIBLE:處于等待隊列中的進程,待資源有效時喚醒,也可由其它進程通過信號(signal)或定時中斷喚醒后進入就緒隊列run-queue。
- TASK_UNINTERRUPTIBLE:處于等待隊列中的進程,待資源有效時喚醒,不可由其它進程通過信號(signal)或定時中斷喚醒。
- TASK_ZOMBIE:表示進程結束但尚未消亡的一種狀態(僵死狀態)。此時,進程已經結束運行且釋放大部分資源,但尚未釋放進程控制塊。
- TASK_STOPPED:進程被暫停,通過其它進程的信號才能喚醒。導致這種狀態的原因有二,或者是對收到SIGSTOP、SIGSTP、SIGTTIN或SIGTTOU信號的反應,或者是受其它進程的ptrace系統調用的控制而暫時將CPU交給控制進程。
- TASK_SWAPPING: 進程頁面被交換出內存的進程。
(2) unsigned long flags;
進程標志:
- PF_ALIGNWARN 打印“對齊”警告信息。
- PF_PTRACED 被ptrace系統調用監控。
- PF_TRACESYS 正在跟蹤。
- PF_FORKNOEXEC 進程剛創建,但還沒執行。
- PF_SUPERPRIV 超級用戶特權。
- PF_DUMPCORE dumped core。
- PF_SIGNALED 進程被信號(signal)殺出。
- PF_STARTING 進程正被創建。
- PF_EXITING 進程開始關閉。
- PF_USEDFPU 該進程使用FPU(SMP only)。
- PF_DTRACE delayed trace (used on m68k)。
(3) long priority;
進程優先級。 Priority的值給出進程每次獲取CPU后可使用的時間(按jiffies計)。優先級可通過系統調用sys_setpriorty改變(在kernel/sys.c中)。
(4) unsigned long rt_priority;
rt_priority給出實時進程的優先級,rt_priority+1000給出進程每次獲取CPU后可使用的時間(同樣按jiffies計)。實時進程的優先級可通過系統調用sys_sched_setscheduler()改變(見kernel/sched.c)。
(5) long counter;
在輪轉法調度時表示進程當前還可運行多久。在進程開始運行是被賦為priority的值,以后每隔一個tick(時鐘中斷)遞減1,減到0時引起新一輪調度。重新調度將從run_queue隊列選出counter值最大的就緒進程并給予CPU使用權,因此counter起到了進程的動態優先級的作用(priority則是靜態優先級)。
(6) unsigned long policy;
該進程的進程調度策略,可以通過系統調用sys_sched_setscheduler()更改(見kernel/sched.c)。調度策略有:
- SCHED_OTHER 0 非實時進程,基于優先權的輪轉法(round robin)。
- SCHED_FIFO 1 實時進程,用先進先出算法。
- SCHED_RR 2 實時進程,用基于優先權的輪轉法。
2. 信號處理 (1) unsigned long signal;
進程接收到的信號。每位表示一種信號,共32種。置位有效。
(2) unsigned long blocked;
進程所能接受信號的位掩碼。置位表示屏蔽,復位表示不屏蔽。
(3) struct signal_struct *sig;
因為signal和blocked都是32位的變量,Linux最多只能接受32種信號。對每種信號,各進程可以由PCB的sig屬性選擇使用自定義的處理函數,或是系統的缺省處理函數。指派各種信息處理函數的結構定義在include/linux/sched.h中。對信號的檢查安排在系統調用結束后,以及“慢速型”中斷服務程序結束后(IRQ#_interrupt(),參見Array。5節“啟動內核”)。
3. 進程隊列指針 (1) struct task_struct *next_task,*prev_task;
所有進程(以PCB的形式)組成一個雙向鏈表。next_task和就是鏈表的前后指針。鏈表的頭和尾都是init_task(即0號進程)。
(2) struct task_struct *next_run,*prev_run;
由正在運行或是可以運行的,其進程狀態均為TASK_RUNNING的進程所組成的一個雙向循環鏈表,即run_queue就緒隊列。該鏈表的前后向指針用next_run和prev_run,鏈表的頭和尾都是init_task(即0號進程)。
(3) struct task_struct *p_opptr,*p_pptr;和struct task_struct *p_cptr,*p_ysptr,*p_osptr; 以上分別是指向原始父進程(original parent)、父進程(parent)、子進程(youngest child)及新老兄弟進程(younger sibling,older sibling)的指針。 4. 進程標識 (1) unsigned short uid,gid;
uid和gid是運行進程的用戶標識和用戶組標識。
(2) int groups[NGROUPS];
與多數現代UNIX操作系統一樣,Linux允許進程同時擁有一組用戶組號。在進程訪問文件時,這些組號可用于合法性檢查。
(3) unsigned short euid,egid;
euid和egid又稱為有效的uid和gid。出于系統安全的權限的考慮,運行程序時要檢查euid和egid的合法性。通常,uid等于euid,gid等于egid。有時候,系統會賦予一般用戶暫時擁有root的uid和gid(作為用戶進程的euid和egid),以便于進行運作。
(4) unsigned short fsuid,fsgid;
fsuid和fsgid稱為文件系統的uid和gid,用于文件系統操作時的合法性檢查,是Linux獨特的標識類型。它們一般分別和euid和egid一致,但在NFS文件系統中NFS服務器需要作為一個特殊的進程訪問文件,這時只修改客戶進程的fsuid和fsgid。
(5) unsigned short suid,sgid;
suid和sgid是根據POSIX標準引入的,在系統調用改變uid和gid時,用于保留真正的uid和gid。
(6) int pid,pgrp,session;
進程標識號、進程的組織號及session標識號,相關系統調用(見程序kernel/sys.c)有sys_setpgid、sys_getpgid、sys_setpgrp、sys_getpgrp、sys_getsid及sys_setsid幾種。
(7) int leader;
是否是session的主管,布爾量。
5. 時間數據成員 (1) unsigned long timeout;
用于軟件定時,指出進程間隔多久被重新喚醒。采用tick為單位。
(2) unsigned long it_real_value,it_real_iner;
用于itimer(interval timer)軟件定時。采用jiffies為單位,每個tick使it_real_value減到0時向進程發信號SIGALRM,并重新置初值。初值由it_real_incr保存。具體代碼見kernel/itimer.c中的函數it_real_fn()。
(3) struct timer_list real_timer;
一種定時器結構(Linux共有兩種定時器結構,另一種稱作old_timer)。數據結構的定義在include/linux/timer.h中,相關操作函數見kernel/sched.c中add_timer()和del_timer()等。
(4) unsigned long it_virt_value,it_virt_incr;
關于進程用戶態執行時間的itimer軟件定時。采用jiffies為單位。進程在用戶態運行時,每個tick使it_virt_value減1,減到0時向進程發信號SIGVTALRM,并重新置初值。初值由it_virt_incr保存。具體代碼見kernel/sched.c中的函數do_it_virt()。
(5) unsigned long it_prof_value,it_prof_incr;
同樣是itimer軟件定時。采用jiffies為單位。不管進程在用戶態或內核態運行,每個tick使it_prof_value減1,減到0時向進程發信號SIGPROF,并重新置初值。初值由it_prof_incr保存。 具體代碼見kernel/sched.c中的函數do_it_prof。
(6) long utime,stime,cutime,cstime,start_time;
以上分別為進程在用戶態的運行時間、進程在內核態的運行時間、所有層次子進程在用戶態的運行時間總和、所有層次子進程在核心態的運行時間總和,以及創建該進程的時間。
6. 信號量數據成員 (1) struct sem_undo *semundo;
進程每操作一次信號量,都生成一個對此次操作的undo操作,它由sem_undo結構描述。這些屬于同一進程的undo操作組成的鏈表就由semundo屬性指示。當進程異常終止時,系統會調用undo操作。sem_undo的成員semadj指向一個數據數組,表示各次undo的量。結構定義在include/linux/sem.h。
(2) struct sem_queue *semsleeping;
每一信號量集合對應一個sem_queue等待隊列(見include/linux/sem.h)。進程因操作該信號量集合而阻塞時,它被掛到semsleeping指示的關于該信號量集合的sem_queue隊列。反過來,semsleeping。sleeper指向該進程的PCB。
7. 進程上下文環境 (1) struct desc_struct *ldt;
進程關于CPU段式存儲管理的局部描述符表的指針,用于仿真WINE Windows的程序。其他情況下取值NULL,進程的ldt就是arch/i386/traps.c定義的default_ldt。
(2) struct thread_struct tss;
任務狀態段,其內容與INTEL CPU的TSS對應,如各種通用寄存器.CPU調度時,當前運行進程的TSS保存到PCB的tss,新選中進程的tss內容復制到CPU的TSS。結構定義在include/linux/tasks.h中。
(3) unsigned long saved_kernel_stack;
為MS-DOS的仿真程序(或叫系統調用vm86)保存的堆棧指針。
(4) unsigned long kernel_stack_page;
在內核態運行時,每個進程都有一個內核堆棧,其基地址就保存在kernel_stack_page中。
8. 文件系統數據成員 (1) struct fs_struct *fs;
fs保存了進程本身與VFS的關系消息,其中root指向根目錄結點,pwd指向當前目錄結點,umask給出新建文件的訪問模式(可由系統調用umask更改),count是Linux保留的屬性,如下頁圖所示。結構定義在include/linux/sched.h中。
(2) struct files_struct *files;
files包含了進程當前所打開的文件(struct file *fd[NR_OPEN])。在Linux中,一個進程最多只能同時打開NR_OPEN個文件。而且,前三項分別預先設置為標準輸入、標準輸出和出錯消息輸出文件。
(3) int link_count;文件鏈(link)的數目。
Array. 內存數據成員
(4) struct mm_struct *mm;
在linux中,采用按需分頁的策略解決進程的內存需求。task_struct的數據成員mm指向關于存儲管理的mm_struct結構。其中包含了一個虛存隊列mmap,指向由若干vm_area_struct描述的虛存塊。同時,為了加快訪問速度,mm中的mmap_avl維護了一個AVL樹。在樹中,所有的vm_area_struct虛存塊均由左指針指向相鄰的低虛存塊,右指針指向相鄰的高虛存塊。 結構定義在include/linux/sched.h中。
10. 頁面管理 (1) int swappable:1;
進程占用的內存頁面是否可換出。swappable為1表示可換出。對該標志的復位和置位均在do_fork()函數中執行(見kerenl/fork.c)。
(2) unsigned long swap_address;
虛存地址比swap_address低的進程頁面,以前已經換出或已換出過,進程下一次可換出的頁面自swap_address開始。參見swap_out_process()和swap_out_pmd()(見mm/vmscan.c)。
(3) unsigned long min_flt,maj_flt;
該進程累計的minor缺頁次數和major缺頁次數。maj_flt基本與min_flt相同,但計數的范圍比后者廣(參見fs/buffer.c和mm/page_alloc.c)。min_flt只在do_no_page()、do_wp_page()里(見mm/memory.c)計數新增的可以寫操作的頁面。
(4) unsigned long nswap;
該進程累計換出的頁面數。
(5) unsigned long cmin_flt,cmaj_flt,cnswap;
以本進程作為祖先的所有層次子進程的累計換入頁面、換出頁面計數。
(6) unsigned long old_maj_flt,dec_flt; (7) unsigned long swap_cnt;
下一次信號最多可換出的頁數。
11. 支持對稱多處理器方式(SMP)時的數據成員 (1) int processor;
進程正在使用的CPU。
(2) int last_processor;
進程最后一次使用的CPU。
(3) int lock_depth;
上下文切換時系統內核鎖的深度。
12. 其它數據成員 (1) unsigned short used_math;
是否使用FPU。
(2) char comm[16];
進程正在運行的可執行文件的文件名。
(3) struct rlimit rlim[RLIM_NLIMITS];
結構rlimit用于資源管理,定義在linux/include/linux/resource.h中,成員共有兩項:rlim_cur是資源的當前最大數目;rlim_max是資源可有的最大數目。在i386環境中,受控資源共有RLIM_NLIMITS項,即10項,定義在linux/include/asm/resource.h中,見下表:
(4) int errno;
最后一次出錯的系統調用的錯誤號,0表示無錯誤。系統調用返回時,全程量也擁有該錯誤號。
(5) long debugreg[8];
保存INTEL CPU調試寄存器的值,在ptrace系統調用中使用。
(6) struct exec_domain *exec_domain;
Linux可以運行由80386平臺其它UNIX操作系統生成的符合iBCS2標準的程序。關于此類程序與Linux程序差異的消息就由exec_domain結構保存。
(7) unsigned long personality;
Linux可以運行由80386平臺其它UNIX操作系統生成的符合iBCS2標準的程序。 Personality進一步描述進程執行的程序屬于何種UNIX平臺的“個性”信息。通常有PER_Linux、PER_Linux_32BIT、PER_Linux_EM86、PER_SVR3、PER_SCOSVR3、PER_WYSEV386、PER_ISCR4、PER_BSD、PER_XENIX和PER_MASK等,參見include/linux/personality.h。
(8) struct linux_binfmt *binfmt;
指向進程所屬的全局執行文件格式結構,共有a。out、script、elf和java等四種。結構定義在include/linux/binfmts.h中(core_dump、load_shlib(fd)、load_binary、use_count)。
(Array) int exit_code,exit_signal;
引起進程退出的返回代碼exit_code,引起錯誤的信號名exit_signal。
(9) int dumpable:1;
布爾量,表示出錯時是否可以進行memory dump。
(10) int did_exec:1;
按POSIX要求設計的布爾量,區分進程是正在執行老程序代碼,還是在執行execve裝入的新代碼。
(11) int tty_old_pgrp;
進程顯示終端所在的組標識。
(12) struct tty_struct *tty;
指向進程所在的顯示終端的信息。如果進程不需要顯示終端,如0號進程,則該指針為空。結構定義在include/linux/tty.h中。
(13) struct wait_queue *wait_chldexit;
在進程結束時,或發出系統調用wait4后,為了等待子進程的結束,而將自己(父進程)睡眠在該隊列上。結構定義在include/linux/wait.h中。
13. 進程隊列的全局變量 (1) current;
當前正在運行的進程的指針,在SMP中則指向CPU組中正被調度的CPU的當前進程:
#define current(0+current_set[smp_processor_id()])/sched.h/
struct task_struct *current_set[NR_CPUS];
(2) struct task_struct init_task;
即0號進程的PCB,是進程的“根”,始終保持初值INIT_TASK。
(3) struct task_struct *task[NR_TASKS];
進程隊列數組,規定系統可同時運行的最大進程數(見kernel/sched.c)。NR_TASKS定義在include/linux/tasks.h中,值為512。每個進程占一個數組元素(元素的下標不一定就是進程的pid),task[0]必須指向init_task(0號進程)??梢酝ㄟ^task[]數組遍歷所有進程的PCB。但Linux也提供一個宏定義for_each_task()(見include/linux/sched.h),它通過next_task遍歷所有進程的PCB:
#define for_each_task(p) \
for(p=&init_task;(p=p-》next_task)!=&init_task;)
(4) unsigned long volatile jiffies;
Linux的基準時間(見kernal/sched.c)。系統初始化時清0,以后每隔10ms由時鐘中斷服務程序do_timer()增1。
(5) int need_resched;
重新調度標志位(見kernal/sched.c)。當需要Linux調度時置位。在系統調用返回前(或者其它情形下),判斷該標志是否置位。置位的話,馬上調用schedule進行CPU調度。
(6) unsigned long intr_count;
記錄中斷服務程序的嵌套層數(見kernal/softirq.c)。正常運行時,intr_count為0。當處理硬件中斷、執行任務隊列中的任務或者執行bottom half隊列中的任務時,intr_count非0。這時,內核禁止某些操作,例如不允許重新調度。
評論
查看更多