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