當(dāng)前位置:首頁 > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > Linux和C語言的學(xué)習(xí)方法你真的知道嗎?
自開班以來已經(jīng)近兩個月了,不能說所教知識都掌握得非常好,但至少還是能跟著老師步伐、理解關(guān)鍵知識點、正確完成作業(yè)的。現(xiàn)在還沒真正開始進(jìn)入硬件方面的學(xué)習(xí),但我相信對基本理論知識及編程開發(fā)的牢固掌握是后續(xù)深入學(xué)習(xí)的前提。因此,趁著現(xiàn)在正處與學(xué)習(xí)進(jìn)度的轉(zhuǎn)折點,有必要對先前的知識作一下概括性總結(jié)。
★L(fēng)inux的使用
開班的第一天,老師就給我們講了為什么要先學(xué)c、學(xué)linux:因為嵌入式的根本就是軟件驅(qū)動硬件,而C語言是最接近硬件的語言、有指針的概念、可以直接操作硬件,另外,功能復(fù)雜的硬件是含有操作系統(tǒng)的,這就需要我們選擇使用廣泛而開源的linux來學(xué)習(xí)。
◇Shell 命令
shell是一個命令行解釋器,命令行格式為:命令名稱、選項、參數(shù),常用的命令有:cd進(jìn)入目錄;ls顯示目錄下的文件;touch、mkdir創(chuàng)建文件、文件夾;mv、cp、rm移動、復(fù)制、刪除文件和文件夾;zip、gzip、tar壓縮和解壓文件;ln創(chuàng)建軟硬鏈接文件。
◇文件管理、用戶管理
Linux是一個多用戶系統(tǒng),它可以用adduser來創(chuàng)建多個用戶,并用su來進(jìn)行不同用戶及用戶與管理員之間的切換;另外,與目錄結(jié)構(gòu)屬于分區(qū)的windows不同,在Linux的文件系統(tǒng)中,分區(qū)屬于目錄結(jié)構(gòu)。
◇軟件管理
ubuntu上的軟件包管理工具apt可以通過網(wǎng)絡(luò)很方便地完成軟件包的獲取、安裝、卸載、查詢等操作。比如,當(dāng)我們在使用putty前需要安裝SSH的時候,就可以通過命令:sudo apt-get update、sudo apt-get install SSH 來安裝。
◇VI 編輯器,GCC 編譯器
Vi是Linux系統(tǒng)中常用的一個文本編輯器,通過vi加上文件名可以對文件創(chuàng)建或編輯。三種模式中:命令模式是我們進(jìn)入編輯器的第一模式,可以對文本進(jìn)行剪切復(fù)制替換刪除操作;輸入模式可以是對文件進(jìn)行常規(guī)編輯;底行模式可以保存文本并退出。vi編輯好的c文件需要被編譯二進(jìn)制文件才可以被機(jī)器識別運(yùn)行,而GCC 編譯器就承載著這樣的功能,它通過預(yù)處理、編譯、匯編、鏈接四個步驟完成該操作。
★C語言編程
C語言學(xué)習(xí)的開始就是掌握基本的語法規(guī)則,主要包括各種基本類型常量變量、運(yùn)算符、控制流、函數(shù)的使用。這部分總的來說沒有什么難度,但有一些容易忽略的細(xì)節(jié)需要留意,如同為單目運(yùn)算的*解引用和++操作同時使用時哪個優(yōu)先運(yùn)算;數(shù)組被定義后其空間大小和首地址不允許改變;要用strcmp()判斷字符串相等而不能直接用==;指針定義后但沒初始化會變成野指針,后續(xù)使用可能發(fā)生段錯誤;使用較大的數(shù)據(jù)時應(yīng)在堆中開辟空間存放以防棧溢出。
☆數(shù)據(jù)結(jié)構(gòu)
數(shù)據(jù)結(jié)構(gòu)就是對數(shù)據(jù)進(jìn)行人為的格式化規(guī)范化儲存,使得數(shù)據(jù)能夠快捷地增刪查改,不同的數(shù)據(jù)結(jié)構(gòu)有不同的優(yōu)缺點及主要用途,如順序表查找快增刪慢而鏈表查找滿增刪快。鑒于內(nèi)核鏈表的重要性及以后使用的廣泛性,在此只做內(nèi)核鏈表的總結(jié)。內(nèi)核鏈表和雙向循環(huán)鏈表類似,與之不同的是,內(nèi)核鏈表將數(shù)據(jù)和鏈表剝離開,并提供了很多的宏和封裝函數(shù)。其中非常重要的是list_for_each()、list_entry(),它們分別實現(xiàn)了對小結(jié)構(gòu)體(循環(huán)鏈表)的遍歷操作、通過小結(jié)構(gòu)體的地址反推找到大結(jié)構(gòu)體的地址,從而通過大結(jié)構(gòu)體得到其下的數(shù)據(jù)域。另外還有l(wèi)ist_add()、list_del_init()封裝實現(xiàn)了對大結(jié)構(gòu)體節(jié)點的插入、孤立刪除,不然自己搭建雙向循環(huán)鏈表的話,就需在頭插node節(jié)點時要寫上經(jīng)典的四句指針域重連接指令:①node->next = head->next;②head->next->pre = node;③node->pre = head;④head->next = node;
☆文件IO
這里的iO指的是內(nèi)存和磁盤間的文件交互,由于linux“一切皆文件的”的特性,其7種類型的文件都是可以被輸入輸出的。其間我們重點學(xué)習(xí)了文件IO和標(biāo)準(zhǔn)IO,他們的主要區(qū)別就是前者直接調(diào)用系統(tǒng)函數(shù)沒有緩沖區(qū),而后者調(diào)用的是封裝好的庫函數(shù)有緩沖區(qū)。一般來說,文件IO是專門給文件使用的,而標(biāo)準(zhǔn)IO是專門給設(shè)備使用的。文件、標(biāo)準(zhǔn)io的打開和關(guān)閉所用的函數(shù)是相似的,只是一個有f一個沒f;但他們的讀寫函數(shù)差別就比較大了,文件io用的是read()、write(),而標(biāo)準(zhǔn)IO根據(jù)輸入輸出是否格式化分為printf、put、scanf、get,具體還會根據(jù)一字一行一塊地讀寫及讀寫目標(biāo)地的不同而有所不同。另外還了解了下利用time()、ctime()來獲取標(biāo)準(zhǔn)時間并轉(zhuǎn)化為可閱讀化時間的時間編程,以及通過lstat()、opendir()、readdir()來查看目錄下的文件屬性。最后介紹了動靜態(tài)庫的概念及制作,前者在文件運(yùn)行時才加載到可執(zhí)行文件中,而后者在編譯時即完成,至于二者制作步驟的話比較復(fù)雜,需要用到的時候再對照著筆記制作好了。
☆進(jìn)程線程
這部分我想是重中之重,畢竟進(jìn)程線程出現(xiàn)的一大動機(jī)就跟人類的無限欲望相關(guān)聯(lián):想要在越短的時間做越多的事情。進(jìn)程就是執(zhí)行中的程序,但與只包含指令和數(shù)據(jù)的程序不同,進(jìn)程有屬于自己的地址空間,里面不僅含有指令段數(shù)據(jù)段,還有動態(tài)的堆棧段,因此多個進(jìn)程可以實現(xiàn)了同一時間做多個任務(wù)。進(jìn)程通過fork()函數(shù)創(chuàng)建,對應(yīng)的PCB由內(nèi)核創(chuàng)建并保存在內(nèi)核空間。盡管多核芯片的出現(xiàn)可以讓多個進(jìn)程真的在同時執(zhí)行任務(wù),但不是所有進(jìn)程都同時處于運(yùn)行狀態(tài)的,更多的進(jìn)程是在極小的時間片段下輪流替換著來工作,至于替換的順序是由cpu調(diào)度機(jī)制決定的,我們無法確定,這也是為什么進(jìn)程擁有異步特性的原因。未在運(yùn)行狀態(tài)的進(jìn)程往往處于隊列就緒等待狀態(tài)或休眠狀態(tài),其它具體的狀態(tài)可以通過命令ps -aux查看。此外,運(yùn)行中的進(jìn)程還分為前臺運(yùn)行和后臺運(yùn)行,如果進(jìn)程是后臺運(yùn)行的話,就不能對它進(jìn)行前臺操作,如不能對它ctrl + c暫停,這時候可以通過fg指令把它轉(zhuǎn)變?yōu)榍芭_運(yùn)行或直接用kill指令終止進(jìn)程。被創(chuàng)建后的進(jìn)程是有生命周期的,它不但可以exit()自行終止進(jìn)程,還可以用exec函數(shù)族中途改為執(zhí)行新的進(jìn)程,殊途同歸,進(jìn)程最后都是要終止的,終止后的進(jìn)程的PCB需要被其父進(jìn)程wait()回收,中間有差錯的話就可能導(dǎo)致孤兒進(jìn)程或僵尸進(jìn)程的出現(xiàn)。
當(dāng)需要進(jìn)程不受干擾地一直在后臺運(yùn)行、周期性地等待或者執(zhí)行某一個任務(wù)的時候,可以將它設(shè)置為守護(hù)進(jìn)程。守護(hù)進(jìn)程不與任何終端關(guān)聯(lián),即使終端關(guān)閉了也還是會照常運(yùn)行,老師教的7步創(chuàng)建法得記熟。值得注意的是,因為守護(hù)進(jìn)程無法往標(biāo)準(zhǔn)輸出打印,中間出錯了也沒人知道,所以得找個地方儲存它的運(yùn)行情況,因此系統(tǒng)日志應(yīng)運(yùn)而生。系統(tǒng)日志可以通過命令cat /var/log/syslog查看。
進(jìn)程可以通過無名管道、有名管道、信號、共享內(nèi)存、消息隊列、信號量來進(jìn)行進(jìn)程間通信,這些通信方式都是在內(nèi)核中得以實現(xiàn)的。具體的函數(shù)及使用筆記上都有詳細(xì)記錄,就不再贅述了。值得留意的是無名有名管道、消息隊列中的同一數(shù)據(jù)是讀了一次就沒有了的,而共享內(nèi)存中的同一數(shù)據(jù)可以被多次讀取。
進(jìn)程和線程都是為了實現(xiàn)計算機(jī)的并發(fā)功能,但是進(jìn)程的創(chuàng)建消亡,及進(jìn)程間的切換都很耗費(fèi)資源,每次切換進(jìn)程都要進(jìn)程上下文切換。線程的優(yōu)勢是多個線程共享指令和全局變量,這就減少了資源管理的消耗,從而更專注于任務(wù)的執(zhí)行。但有優(yōu)點就有缺點,資源的共享可能會致使多個線程同時對臨界資源進(jìn)行操作,從而導(dǎo)致運(yùn)算結(jié)果的不準(zhǔn)確。為了解決這一問題,出現(xiàn)了線程的互斥與同步。線程互斥利用mutex鎖在臨界區(qū)的前后分別pthread_mutex_lock()上鎖和pthread_mutex_destroy()解鎖,實現(xiàn)同一時間只允許一個線程操作臨界資源。線程的同步用的是信號量,相當(dāng)于加上了數(shù)量的線程的互斥,通過合理地使用p+1、v-1操作使得多個線程按一定次序運(yùn)行。
以上即為近兩個月來重要知識的概括性總結(jié)。