標籤: 網頁設計

  • 第五屆中國國際新能源汽車及配套設施展覽會

    日期:2014年11月20 – 22日
    地點:中國國際展覽中心(三元橋)

    NEVIP2014概況

    開館時間:週四—週六
    展會主題:匯新興、享低碳生活
    展會規模:22000 m2(1、2、3、4、5館)
    汽車(天然氣汽車)展區14000m2+ 配套設施展區3000m2+ 電機及零部件展區3000m2+ 電池展區2000m2;參展資格:註冊資金需在500萬人民幣以上。
    展會活動:中國國際新能源汽車產業促進推廣周+20餘場專題活動
    同期舉辦:第六屆中國國際汽車製造業博覽會
    企業數量:200家以上、國際企業(含港、澳、台):30%以上
    觀眾數量:超過8000名與會者、超過70%與會者來自中國以及亞太地區
    全球彙聚:中國、奧地利、比利時、加拿大、捷克共和國、丹麥、芬蘭、法國、德國、希臘、香港特別行政區、以色列、義大利、日本、韓國、荷蘭、紐西蘭、俄羅斯、新加坡、西班牙瑞典、瑞士、台灣地區、英國等31個國家及地區以上企業構成。
    主辦單位:中國國際貿易促進委員會、中國汽車技術研究中心、中國電池工業協會
    支援單位:國家發展和改革委員會、國家科技部、 國家財政部、國家工信部、國家能源局、國務院發展研究中心
    協辦單位:中國汽車工業協會、中國汽車工程學會、世界電動車協會、亞洲電池協會、中國城市發展研究會、中國汽車工程學會電動車分會、清華大學汽車研究所、加中貿易理事會、德國工商總會
    合作單位:中國汽車工業工程公司、機械工業部第四設計研究院、機械工業部第九設計研究院、東風汽車設計研究院、中國汽車工程研究院、北京汽車研究院 
    承辦單位:中國國際貿易促進委員會經濟資訊部、中國國際經濟技術合作諮詢公司、東都國際展覽(北京)有限公司、中國汽車技術研究中心汽車技術情報研究所

    NEVIP行業背景

    隨著國際不可再生資源的日益匱乏,在能源與環保的壓力下,新能源汽車無疑將成為未來汽車的發展方向。根據出臺的《汽車產業調整和振興規劃》提出的發展目標,今後三年內我國要形成50萬輛純電動、充電式混合動力和普通型混合動力等新能源汽車產能,新能源汽車銷量占乘用車銷售總量的5%左右,到2030年,電動汽車保有量占汽車保有量50%以上,年生產銷售電動汽車1000萬—1950萬輛。而要實現這一目標,政府的扶持將會是電動汽車產業在現階段得以穩步發展的最有力的驅動。

    NEVIP展會介紹

    中國國際新能源汽車及配套設施展覽會(簡稱 nevip),創辦於2010年,由中國國際貿易促進委員牽頭舉辦,至今已成功舉辦4屆,自2014年起,得到了中國汽車技術研究中心、中國電池工業協會的加盟合作,與中國貿促會共同主辦,之後被定位於中國新能源汽車領域的國家級、國際性展覽盛會。 

    nevip舉辦以來共吸引了來自30多國家和地區的500家展商,世界500強企業9家,專業觀眾累計超過40,000人次,展會面積達到50,000平米,目前已於17個國家大使館、商協會建立長期合作關係。 

    nevip歷屆國內外著名參展企業有北汽、一汽、廣汽、長安、通用、日產、恒通、比亞迪、陸地方舟、大連森穀、寶雅、嘉遠、京儀敬業、永泰、貝迪、南方軸承、銀巢等整車及關鍵部件企業和ABB、西門子、施耐德、艾默生、Better Place、韓國KODI-S、德國拜耳、魏德米勒、普天、奧特迅、科陸、廣州南方電力、魯能、優科利爾、電巴、力神、突破電氣、嘉兆科技、艾普斯、凱翔、匯千、旗翔、凱源新能、宇能、亨通、上海永乾等基礎設施企業。

    nevip觀眾主要來自行業:汽車公司、電力公司、石油公司、能源公司、公交公司、計程車公司、汽車諮詢公司、電力專案承包和管理公司及投資商、貿易商、代理機構、分銷商、施工單位、政府機構、行業協會、規劃設計單位、高等院校、 研發基地、技術與工程人員等。

    展會有新華社、中央電視臺、中國日報、人民日報、光明日報、中國經營報、中國汽車報、中國能源報、汽車要聞、美國湯森路透、美國《The Truth About Cars》、財富雜誌、《美國汽車新聞•中國》、德國《auto motor undsport》、巴西《Brasil Economico》、英國《AutoCar》、《China car times》、AI《汽車製造業》、第一財經日報、華爾街日報及新華網、新浪、搜狐、人民網等國內外上百家媒體報導。

    中國國際新能源汽車及配套設施展覽會(nevip 2014),將於2014年11月20日-22日在北京•中國國際展覽中心(三元橋)舉辦,歡迎您屆時參觀參展!

    NEVIP2014展示內容 

    • 新能源汽車展區
      新能源汽車:混合動力、純電動(汽車、客車、公車、校車等),低排放、節能型汽車、電動代步車、電動特種車(環衛車、電力車、郵政車、小型客貨車、高爾夫車、房車、叉車、搬運車、牽引車、旅遊觀光車、醫療車、警用車等),氫能燃料電池汽車等; 
    • 零部件展區 
      零部件:電池、電機、電控:動力電池、儲能電池、電池管理系統BMS、鋰電池、燃料電池、超級電容器,無刷直流電機和永磁同步電機、開關磁阻電機,電驅動系統、整車匯流排與控制系統、動力總成等;低排放節能型發動機、混合動力發動機,電力電容器、電動助力轉向、電動空調、飛輪、逆變器、輪轂輪胎、儀錶儀盤、車燈、線束、車載電子、檢測修復設備、監控、防護儀器、內外裝飾及座椅等;
    • 配套基礎設施建設展區
      配套基礎設施建設:電動汽車充換電新模式、新技術、新產品;無線充電方案;充換電站智慧型網路專案規劃及成果展示;充電站配電設備、直接充換電設備、管理輔助設備、能源管理系統;換電機器人、機械臂、換電搬運設備、電池倉儲充電架;停車場充電設施、智慧監控、相關技術、連接器、線纜等; 
    • 電池技術展區
      電池及技術裝備:鋰離子電池、聚合物鋰離子電池、燃料電池、釩電池、超級電容器、鈉硫電池、鉛酸蓄電池;各系列新型動力、儲能電池;新型電池生產設備、測試儀器、充電器;新型電池材料及零配件;電池環保設備、回收處理技術等; 

    NEVIP 2014怎麼收費

    標準展位:外資企業:RMB 22000/9平方米  內資企業:RMB 16800/9平方米
    光地展位:外資企業:RMB 2200/每平方米  內資企業:RMB1600/每平方米
    展位搭建說明:光地起租面積為36平方米,展商可自行選擇展館內以規劃好相應面積的展位,並自行雇傭搭建商進行展位的設計與搭建,或選擇標準展位搭建。標準展位包含楣板、牆板、地毯 5A/220V
    電源插座展位元照明,展位元日常清潔基本傢俱配置。(注:雙開口展位另加收10%展位費)

    NEVIP 2014技術交流會

    展會期間,組委會將協助參展企業在展館會議室舉辦技術交流講座,內容由企業自定,每場聽眾60-80人,由企業自行邀請,組委會協助組織,並於2014年10月1日前將講座題目主要內容主講人姓名提交組委會。講座場次有限,報滿為止,每場講座60分鐘,費用¥8,000元/場。

    怎樣在NEVIP 2014中國最具影響力的新能源汽車展會上凸顯您的品牌?

    我們提供的一攬子贊助計畫將能最大程度滿足您市場宣傳的需要,助推您的企業:

    • 在會展宣傳資料中充分介紹
    • 在全新的NEVIP 2014網站上作線上展示
    • 觀眾、參展商胸卡、掛帶、手提袋贊助
    • 論壇相關贊助
    • 現場拱門、看板、旗杆廣告贊助

    詳情請登錄官方網址 或聯繫我們:
    地址:中國北京市東城區和平里東土城路甲14號8層  郵編:100013
    電  話:+86 010-52338120
    傳  真:+86 010 -62500724
    E-mail:

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※推薦評價好的iphone維修中心

  • 中國正考慮降低電動汽車進口關稅

    據中新網報道,中國政府正考慮進行電動汽車稅收改革。中國政府官員日前會見特斯拉(Tesla)首席執行官馬斯克(Musk Elon),均表示中國將支持電動汽車產業。

    科技部部長萬鋼在北京會見馬斯克時表示,中國政府正在考慮電動汽車在稅收方面的改革,比如在進口關稅方面會有別於傳統汽車的進口,但具體細則現在還在制定之中。

    工業和信息化部部長苗圩會見馬斯克時則表示,中國政府高度重視新能源汽車產業的發展,希望特斯拉公司發揮自身優勢,不斷創新,加強與中國企業的合作。

    他同時指出,中國政府正在制定政策,幫助像特斯拉一樣的企業進入中國,促進電動汽車產業在中國的發展。

    馬斯克亦表示,特斯拉公司非常重視中國市場,願加強與中國企業的合作。特斯拉已經在北京與上海建設充電站,電力來源為光伏與電網的結合,可實現24小時不間斷充電。」特斯拉未來還計畫建立超級充電網路。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 特斯拉與阿里及租車公司合作 方便中國民眾購買電動車

    電動汽車大廠特斯拉(Tesla)日前分別與阿里巴巴旗下支付寶及一嗨租車合作,中國大陸客戶不僅可用支付寶訂車付款,還可以租用特斯拉的電動車。首批兩輛Model S電動車已經正式交付,下一批將會在5月份到達。

    除了阿里巴巴與一嗨租車搶著與特斯拉合作,電信巨頭之一的中國聯通日前也傳出與特斯拉中國合作的消息,將由聯通為特斯拉的電動車提供車載資訊服務。

    其實電動車在大陸已經銷售多年,長城、比亞迪等大陸本土車廠都有製造電動汽車,但整體銷量始終未見起色。特斯拉卻在大陸獲得了超高人氣。

    根據中國汽車工業協會的統計,2013年全國的純電動車銷量只有14,604輛,僅占全年汽車銷量的不到1%。此外,在大陸的電動車銷售業績中,大多屬於商用載客或公務車輛,民眾主動購買的純電動車數量相當稀少。

    特斯拉去年全年銷售了23,500輛電動汽車。特斯拉創辦人Elon Musk日前表示,預估今年公司在全球的銷量將超過30,000輛,其中有5,000輛會來自大陸市場。該公司更計畫在大陸設立超級充電站與電動車產線。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

  • 比亞迪交付首部於美國工廠生產的純電動大巴

    據中新社報導,昨(28)日,比亞迪(BYD)首部在美國蘭卡斯特電動汽車工廠組裝制造的電動大巴車下線並交付使用。該工廠是美國首個中國獨資的清潔能源汽車工廠,於去年5月在加州南部城市蘭卡斯特落成。

    新生產的電動大巴整車長12米,最多可以乘坐60名乘客,續航裏程155英裏(約250公裏),充電時間需3-5個小時。

    加州州長傑瑞-布朗表示,比亞迪的清潔能源大巴為加州環境向好發展以及中美經貿合作發展起到了良好的促進作用。

    盡管比亞迪開拓美國市場的過程並非一帆風順,但在加州各級政府和合作夥伴的共同努力下,比亞迪成功生產出首輛美國本土制造、無污染、零排放、全電動的大巴。

    這不僅有利于創造就業,促進經濟增長,造福當地社區及加州,同時也樹立起了中國投資者的良好形象,有利于進一步增強中國投資者對于加州的投資信心。

    中國駐洛杉磯總領館卞立新代總領事表示,當前,中美關係進入了一個新的發展時期,經貿合作已成為兩國關係的最大亮點。據統計,去年來南加州投資的中國企業比前一年增長76%。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?

  • 明年京港澳高速全線將建成電動汽車充電服務區

    據新華社報導,中國大陸湖北省即將啟動京港澳高速湖北段電動汽車快速充電設施建設。到2015年,京港澳高速公路全線將建成智慧充電服務區,屆時電動汽車可從北京開到香港。

    全長2285公里的京港澳高速是中國南北交通大動脈。從今年起,國家電網公司將在京港澳高速北京至湖南段全長1500公里內,平均每38公里建設一對電動汽車智慧充電服務區,並將聯合南方電網公司和社會資本在2015年實現全線覆蓋。

    目前,按照國家電網統一部署,湖北省電力公司已與湖北省交通投資有限公司對接,雙方將於近期簽署戰略合作協議,儘快啟動湖北高速公路沿線充電網路建設。

    據瞭解,在京港澳高速湖北段,每個快充站將部署4臺120千瓦分體式充電機,可同時供8臺電動車充電,一般只需20分鐘即可充電80%,可提供150至200公里續航里程。

    按照國家電網公司智慧充換電網路發展規劃,2020年將全面建成以「四縱四橫」(四縱:沈海、京滬、京臺、京港澳,四橫:青銀、連霍、滬蓉、滬昆)為支撐的、覆蓋國家電網公司經營區內所有示範城市的城際快充網路。

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※幫你省時又省力,新北清潔一流服務好口碑

    ※別再煩惱如何寫文案,掌握八大原則!

  • TOYOTA將與FirstElement合作建立加氣站

    TOYOTA將與FirstElement合作建立加氣站

    據AUTONET報導,TOYOTA將與能源公司FirstElement攜手合作加氫站網絡的架設,預計2015-2016年能夠建成20多處的加氣站,並能在2024年實現擴建至100座的計畫。

    TOYOTA於2013年底東京車展發表準量產版的FCV Concept,此後又藉由年初的2014 CES消費電子展預告2015年將率先投入北美市場販售,因此對於加氫站等後勤網絡的建設排上日程。

    其實在過去的20年來,TOYOTA就已持續針對氫燃料電池進行研發,自2002年以來便投入一系列的測試車輛於北美進行實測,隨著技術的突破,使得氫燃料電池技術成本大幅下修,終於達到原廠量產的預期。

    儘管FCV(氫燃料電池車)最終量產版本的相關數據原廠尚未公開,但參考FCV Concept所呈現的數據就相當令人滿意。

    動力來源為分別藏在車身底下的氫燃料儲存槽及電池,具備等同於136hp馬力的100kW輸出功率,需花費10秒才能完成100km/h的加速衝刺,滿電的情況下續航力約可達到482km,而且僅需3-5分鐘的時間便能將儲存槽加滿,省去了傳統電池充電耗時的問題。

    重點是氫燃料電池是以氫或含氫物質結合氧所形成的一種燃料電池,在化學反應之後僅會產生電流及水且完全沒有污染。

    動力來源為分別藏在車身底下的氫燃料儲存槽及電池(圖片來源:AUTONET)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

  • 拿來即用:用C+JS結構來處理JSON數據

    拿來即用:用C+JS結構來處理JSON數據

    【面對的問題】

            在物聯網產品的開發過程中,對JSON格式的數據處理是一個強需求,例如亞馬遜的 AWS IOT平台,設備與後台之間的通訊數據都是JSON格式,先瞄一眼大概的樣子:

         這是一個真實產品的通訊數據,設備端的代碼C代碼中利用cJSON這個開源工具來完成JSON字符的解析和組裝工作。代碼我這裏就不貼了,解析函數很長,要滾動好多次鼠標滑輪。而且一不注意釋放資源就會發生內存泄漏!

        那麼,是否有更好的方式來解決這個問題呢?

        答案就是這篇文章介紹的duktape引擎!

    【Duktape簡介】

        這裏只是簡單介紹下duktape,詳細的介紹大家自己去google。

        Duktape 是一個嵌入式 Javascript引擎,專註於可移植性和空間佔用。

        易於集成到C/C++項目中,使用API實現C代碼與JS代碼的雙向調用。

     

    【代碼說明】

    1.文件說明

     

     

        duktape.c:引擎主要C文件。

        duktape.h:引擎頭文件。

        main.c      :  main函數所在文件。

       main.js      :Javascript文件,處理業務邏輯的代碼就放在這裏。

        Makefile   :  編譯腳本。

        miniz.c     :有時候為了js代碼的保密,不能把js源碼放到最終產品中,需要壓縮和混淆;加載的時候再進行解壓。

    2.核心步驟 

     

        當C代碼中需要對JSON格式的字符串進行處理時,把JSON數據通過棧結構傳給JS程序,在JS程序中處理數據之後,把處理結果再返回給C程序中。

        在JS程序中,如果有些操作無法處理(例如:發送數據給串口),那麼就調用C程序中的函數來處理。

    3.代碼說明

     

     

    【測試環境】

    1. x86系統

        我是在  Ubuntu16.04 下測試的,使用系統自帶 gcc 編譯器。

    2.嵌入式系統

        只需要把編譯器換成對應的交叉編譯器即可。

     

    【END】

    1.這是原創文章,請尊重版權。如需轉載,請保留全部內容並註明來源。如果方便的話,請聯繫我確認。

    2.文章中如有錯誤,或者希望交流、探討相關內容,非常歡迎聯繫我。

    3.郵箱:sewain@126.com

    4.公眾號:IOT物聯網小鎮

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※推薦評價好的iphone維修中心

  • Linux Systemd 詳細介紹: Unit、Unit File、Systemctl、Target

    Linux Systemd 詳細介紹: Unit、Unit File、Systemctl、Target

    Systemd

    簡介

    CentOS 7 使用 Systemd 替換了SysV

    Ubuntu 從 15.04 開始使用 Systemd

    Systemd 是 Linux 系統工具,用來啟動守護進程,已成為大多數發行版的標準配置

    特點

    優點:

    1. 按需啟動進程,減少系統資源消耗

    2. 并行啟動進程,提高系統啟動速度

      在 SysV-init 時代,將每個服務項目編號,依次執行啟動腳本。Ubuntu 的 Upstart 解決了沒有直接依賴的啟動之間的并行啟動。而 Systemd 通過 Socket 緩存、DBus 緩存和建立臨時掛載點等方法進一步解決了啟動進程之間的依賴,做到了所有系統服務併發啟動。對於用戶自定義的服務,Systemd 允許配置其啟動依賴項目,從而確保服務按必要的順序運行。

      SystemV Upstart 參考上一篇博文:Linux 初始化系統 SystemV Upstart

    3. 使用 CGroup 監視和管理進程的生命周期

      CGroup 提供了類似文件系統的接口,當進程創建子進程時,子進程會繼承父進程的 CGroup。因此無論服務如何啟動新的子進程,所有的這些相關進程都會屬於同一個 CGroup

      在 Systemd 之前的主流應用管理服務都是使用 進程樹 來跟蹤應用的繼承關係的,而進程的父子關係很容易通過 兩次 fork 的方法脫離。

      而 Systemd 則提供通過 CGroup 跟蹤進程關係,引補了這個缺漏。通過 CGroup 不僅能夠實現服務之間訪問隔離,限制特定應用程序對系統資源的訪問配額,還能更精確地管理服務的生命周期

    4. 統一管理服務日誌

    5. 支持快照和系統恢復

    缺點:

    1. 過於複雜,與操作系統的其他部分強耦合,違反”keep simple, keep stupid”的Unix 哲學

    架構圖

    Unit(單元|服務)

    Systemd 可以管理所有系統資源:

    1. 將系統資源劃分為12類
    2. 將每個系統資源稱為一個 Unit。Unit 是 Systemd 管理系統資源的基本單位
    3. 使用一個 Unit File 作為 Unit 的單元文件,Systemd 通過單元文件控制 Unit 的啟動

    例如,MySQL服務被 Systemd 視為一個 Unit,使用一個 mysql.service 作為啟動配置文件

    Unit File(單元文件|配置文件)

    單元文件中包含該單元的描述、屬性、啟動命令等

    類型

    Systemd 將系統資源劃分為12類,對應12種類型的單元文件

    系統資源類型 單元文件擴展名 單元文件描述
    Service .service 封裝守護進程的啟動、停止、重啟和重載操作,是最常見的一種 Unit 文件
    Target .target 定義 target 信息及依賴關係,一般僅包含 Unit 段
    Device .device 對於 /dev 目錄下的硬件設備,主要用於定義設備之間的依賴關係
    Mount .mount 定義文件系統的掛載點,可以替代過去的 /etc/fstab 配置文件
    Automount .automount 用於控制自動掛載文件系統,相當於 SysV-init 的 autofs 服務
    Path .path 用於監控指定目錄或文件的變化,並觸發其它 Unit 運行
    Scope .scope 這種 Unit 文件不是用戶創建的,而是 Systemd 運行時產生的,描述一些系統服務的分組信息
    Slice .slice 用於表示一個 CGroup 的樹
    Snapshot .snapshot 用於表示一個由 systemctl snapshot 命令創建的 Systemd Units 運行狀態快照,可以切回某個快照
    Socket .socket 監控來自於系統或網絡的數據消息
    Swap .swap 定義一個用戶做虛擬內存的交換分區
    Timer .timer 用於配置在特定時間觸發的任務,替代了 Crontab 的功能

    對於操作單元文件的命令,如果缺省擴展名,則默認.service擴展名

    而操作 target 的命令,例如 isolate,則默認.target擴展名

    語法

    單元文件的語法來源於 XDG桌面入口配置文件.desktop文件

    Unit 文件可以分為三個配置區段:

    • Unit 段:所有 Unit 文件通用,用來定義 Unit 的元數據,以及配置與其他 Unit 的關係
    • Install 段:所有 Unit 文件通用,用來定義如何啟動,以及是否開機啟動
    • Service 段:服務(Service)類型的 Unit 文件(後綴為 .service)特有的,用於定義服務的具體管理和執行動作

    單元文件中的區段名和字段名大小寫敏感

    每個區段內都是一些等號連接的鍵值對(鍵值對的等號兩側不能有空格)

    Unit 段

    主要字段如下:

    • Description:當前服務的簡單描述

    • Documentation:文檔地址,可以是一個或多個文檔的 URL 路徑

      【依賴關係】

    • Requires:與其它 Unit 的強依賴關係,如果其中任意一個 Unit 啟動失敗或異常退出,當前 Unit 也會被退出

    • Wants:與其它 Unit 的弱依賴關係,如果其中任意一個 Unit 啟動失敗或異常退出,不影響當前 Unit 繼續執行

      只涉及依賴關係,默認情況下 兩個 Unit 同時啟動

      【啟動順序】

    • After:該字段指定的 Unit 全部啟動完成以後,才會啟動當前 Unit

    • Before:該字段指定的 Unit 必須在當前 Unit 啟動完成之後再啟動

      只涉及啟動順序,不影響啟動結果和運行情況

    • Binds To:與 Requires 相似,該字段指定的 Unit 如果退出,會導致當前 Unit 停止運行

    • Part Of:一個 Bind To 作用的子集,僅在列出的 Unit 失敗或重啟時,終止或重啟當前 Unit,而不會隨列出Unit 的啟動而啟動

    http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.unit.5.html

    Install 段

    主要字段如下:

    • WantedBy:它的值是一個或多個 target,執行enable命令時,符號鏈接會放入/etc/systemd/system目錄下以 target 名 + .wants後綴構成的子目錄中
    • RequiredBy:它的值是一個或多個 target,執行enable命令時,符號鏈接會放入/etc/systemd/system目錄下以 target 名 + .required後綴構成的子目錄中
    • Alias:當前 Unit 可用於啟動的別名
    • Also:當前 Unit 被 enable/disable 時,會被同時操作的其他 Unit

    http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.unit.5.html

    Service 段

    主要字段如下:

    【啟動類型】

    • Type:定義啟動時的進程行為。它有以下幾種值。
      • Type=simple:默認值,ExecStart字段啟動的進程為主進程
        • 服務進程不會 fork,如果該服務要啟動其他服務,不要使用此類型啟動,除非該服務是 socket 激活型
      • Type=forkingExecStart字段將以fork()方式從父進程創建子進程啟動,創建後父進程會立即退出,子進程成為主進程。
        • 通常需要指定PIDFile字段,以便 Systemd 能夠跟蹤服務的主進程
        • 對於常規的守護進程(daemon),除非你確定此啟動方式無法滿足需求,使用此類型啟動即可
      • Type=oneshot:只執行一次,Systemd 會等當前服務退出,再繼續往下執行
        • 適用於只執行一項任務、隨後立即退出的服務
        • 通常需要指定RemainAfterExit=yes字段,使得 Systemd 在服務進程退出之後仍然認為服務處於激活狀態
      • Type=dbus:當前服務通過 D-Bus 信號啟動。當指定的 BusName 出現在 DBus 系統總線上時,Systemd認為服務就緒
      • Type=notify:當前服務啟動完畢會發出通知信號,通知 Systemd,然後 Systemd 再啟動其他服務
      • Type=idle:Systemd 會等到其他任務都執行完,才會啟動該服務。
        • 一種使用場合是:讓該服務的輸出,不與其他服務的輸出相混合

    【啟動行為】

    • ExecStart:啟動當前服務的命令

      ExecStart=/bin/echo execstart1
      ExecStart=
      ExecStart=/bin/echo execstart2
      

      順序執行設定的命令,把字段置空,表示清除之前的值

    • ExecStartPre:啟動當前服務之前執行的命令

    • ExecStartPost:啟動當前服務之後執行的命令

    • ExecReload:重啟當前服務時執行的命令

    • ExecStop:停止當前服務時執行的命令

    • ExecStopPost:停止當前服務之後執行的命令

    • RemainAfterExit:當前服務的所有進程都退出的時候,Systemd 仍認為該服務是激活狀態

      • 這個配置主要是提供給一些並非常駐內存,而是啟動註冊后立即退出,然後等待消息按需啟動的特殊類型服務使用的
    • TimeoutSec:定義 Systemd 停止當前服務之前等待的秒數

      注:所有的啟動設置之前,都可以加上一個連詞號(-),表示”抑制錯誤”,即發生錯誤的時候,不影響其他命令的執行。比如,EnvironmentFile=-/etc/sysconfig/sshd(注意等號後面的那個連詞號),就表示即使/etc/sysconfig/sshd文件不存在,也不會拋出錯誤。

    【重啟行為】

    • RestartSec:Systemd 重啟當前服務間隔的秒數
    • KillMode:定義 Systemd 如何停止服務,可能的值包括:
      • control-group(默認值):當前控制組裡面的所有子進程,都會被殺掉
      • process:只殺主進程(sshd 服務,推薦值)
      • mixed:主進程將收到 SIGTERM 信號,子進程收到 SIGKILL 信號
      • none:沒有進程會被殺掉,只是執行服務的 stop 命令。
    • Restart:定義何種情況 Systemd 會自動重啟當前服務,可能的值包括:
      • no(默認值):退出后不會重啟
      • on-success:只有正常退出時(退出狀態碼為0),才會重啟
      • on-failure:非正常退出時(退出狀態碼非0),包括被信號終止和超時,才會重啟(守護進程,推薦值)
      • on-abnormal:只有被信號終止和超時,才會重啟(對於允許發生錯誤退出的服務,推薦值)
      • on-abort:只有在收到沒有捕捉到的信號終止時,才會重啟
      • on-watchdog:超時退出,才會重啟
      • always:不管是什麼退出原因,總是重啟

    【上下文】

    • PIDFile:指向當前服務 PID file 的絕對路徑。

    • User:指定運行服務的用戶

    • Group:指定運行服務的用戶組

    • EnvironmentFile:指定當前服務的環境參數文件。該文件內部的key=value鍵值對,可以用$key的形式,在當前配置文件中獲取

      啟動sshd,執行的命令是/usr/sbin/sshd -D $OPTIONS,其中的變量$OPTIONS就來自EnvironmentFile字段指定的環境參數文件。

    http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.service.5.html

    佔位符

    在 Unit 文件中,有時會需要使用到一些與運行環境有關的信息,例如節點 ID、運行服務的用戶等。這些信息可以使用佔位符來表示,然後在實際運行中動態地替換為實際的值。

    詳細了解見 https://cloud.tencent.com/developer/article/1516125

    模板

    在現實中,往往有一些應用需要被複制多份運行,就會用到模板文件

    模板文件的寫法與普通單元文件基本相同,只是模板文件名是以 @ 符號結尾。例如:apache@.service

    通過模板文件啟動服務實例時,需要在其文件名的 @ 字符後面附加一個用於區分服務實例的參数字符串,通常這個參數是用於監控的端口號或控制台 TTY 編譯號

    systemctl start apache@8080.service
    

    Systemd 在運行服務時,首先尋找跟單元名完全匹配的單元文件,如果沒有找到,才會嘗試選擇匹配模板

    例如上面的命令,System 首先會在約定的目錄下尋找名為 apache@8080.service 的單元文件,如果沒有找到,而文件名中包含 @ 字符,它就會嘗試去掉後綴參數匹配模板文件。對於 apache@8080.service,Systemd 會找到 apache@.service 模板文件,並通過這個模板文件將服務實例化。

    詳細了解見 https://cloud.tencent.com/developer/article/1516125

    狀態

    systemctl list-unit-files 將會列出文件的 state,包括 static, enabled, disabled, masked, indirect

    • masked

      service軟鏈接到/dev/null

      該單元文件被禁止建立啟動鏈接

    • static

      該單元文件沒有[Install]部分(無法執行),只能作為其他配置文件的依賴

    • enabled

      已建立啟動鏈接

    • disabled

      沒建立啟動鏈接

    https://askubuntu.com/a/731674

    示例

    1. 關掉觸摸板配置文件

      Unit]
      Description=Switch-off Touchpad
      
      [Service]
      Type=oneshot
      ExecStart=/usr/bin/touchpad-off start
      ExecStop=/usr/bin/touchpad-off stop
      RemainAfterExit=yes
      
      [Install]
      WantedBy=multi-user.target
      
      • oneshot 表明這個服務只要運行一次就夠了,不需要長期運行
      • RemainAfterExit字段設為yes,表示進程退出以後,服務仍然保持執行。這樣的話,一旦使用systemctl stop命令停止服務,ExecStop指定的命令就會執行,從而重新開啟觸摸板

    Systemd 內建命令

    systemd-analyze

    Analyze and debug system manager, If no command is passed, Systemd-analyze time is implied

    https://www.freedesktop.org/software/systemd/man/systemd-analyze.html

    systemd-analyze time

    查看初始化耗時

    systemd-analyze blame

    打印所有運行單元,按它們初始化的時間排序。此信息可用於優化啟動時間。注意,輸出可能具有誤導性,因為一個服務的初始化可能非常緩慢,因為它等待另一個服務的初始化完成

    systemd-run

    將一個指定的服務變成後台服務

    未測試

    參考 https://www.freedesktop.org/software/systemd/man/systemd-run.html

    systemctl 系統服務管理命令

    systemctl是 Systemd 的主命令,用於管理系統

    與 service 命令的區別

    1. systemctl 融合了 service 和 chkconfig 的功能
    2. 在 Ubuntu18.04 中沒有自帶 chkconfig 命令;service 命令實際上重定向到 systemctl 命令
    動作 SysV Init 指令 Systemd 指令
    啟動某服務 service httpd start systemctl start httpd
    停止某服務 service httpd stop systemctl stop httpd
    重啟某服務 service httpd restart systemctl restart httpd
    檢查服務狀態 service httpd status systemctl status httpd
    刪除某服務 chkconfig –del httpd 停掉應用,刪除其配置文件
    使服務開機自啟動 chkconfig –level 5 httpd on systemctl enable httpd
    使服務開機不自啟動 chkconfig –level 5 httpd off systemctl disable httpd
    查詢服務是否開機自啟 chkconfig –list | grep httpd systemctl is-enabled httpd
    加入自定義服務 chkconfig –add test systemctl load test
    显示所有已啟動的服務 chkconfig –list systemctl list-unit-files | grep enabled

    參數

    --all

    显示加載到內存的所有單元

    --type

    -t --type=

    显示指定類型(12種類型)的單元

    --state

    --state=

    显示指定狀態的單元或單元文件

    • 單元狀態

      輸入 systemctl list-units --stateTab鍵,显示所有可用的值

    • 單元文件狀態

      另外還可以用 enabled static disabled 等systemctl list-unit-files 显示的狀態

    --failed

    --state=failed

    显示加載失敗的單元

     systemctl --failed
    
    --version

    打印 Systemd 版本

    lfp@legion:/lib/systemd/system$ systemctl --version
    Systemd 237
    +PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid
    

    單元命令

    我的理解

    • systemd 對單元的管理,不涉及單元文件自身屬性和內容
    list-units

    相當於systemctl

    列出當前已加載的單元(內存)

    默認情況下僅显示處於激活狀態(正在運行)的單元

    UNIT 單元名

    LOAD 加載狀態

    ACTIVE SUB 執行狀態(大狀態 子狀態)

    DESCRIPTION 描述

    start

    啟動單元

    systemctl start mysql.service
    
    stop

    停止單元

    systemctl stop mysql.service
    
    kill

    殺掉單元進程

    systemctl kill mysql.service
    
    reload

    不終止單元,重新加載 針對該單元的 運行配置文件,而不是 針對 systemd的 該單元的啟動配置文件

    例如啟動 MySQL 服務,reload 可以在不停止服務的情況下重載 MySQL 的配置文件 my.cnf

    restart

    重啟單元

    該單元在重啟之前擁有的資源不會被完全清空,比如文件描述符存儲設施

    systemctl reload mysql.service
    
    status

    status [unit | PID]

    显示單元或進程所屬單元的運行信息

    systemctl status mysql.service
    

    Loaded行:配置文件的位置,是否設為開機啟動

    Active行:表示正在運行

    Main PID行:主進程ID

    CGroup塊:應用的所有子進程

    日誌塊:應用的日誌

    is-active

    判斷指定的單元是否處於激活狀態

    # 默認會打印當前單元的狀態,可以通過 --quiet 參數取消打印
    lfp@legion:~$ systemctl is-active mysql
    active
    
    is-failed

    判斷指定的單元是否處於啟動失敗狀態

    lfp@legion:~$ systemctl is-failed mysql
    active
    
    list-dependencies

    查看單元之間的依賴關係

    systemctl list-dependencies graphical.target 
    systemctl list-dependencies mysql.service
    
    show

    show --property= Unit <==> show -p Unit

    显示單元所有底層參數

    lfp@legion:~$ systemctl show -p MainPID mysql
    MainPID=1061
    
    set-property

    在單元啟動的時候設置運行時的某個屬性,立即生效,並保存在磁盤中作為啟動配置

    如果添加了--runtime則重啟后失效

    並非所有的屬性都可以設置,只是 systemd.resource-control 包含的屬性

    isolate

    切換到某個 target(系統狀態),立即停止該 target 未包含的單元進程。也可以理解為切換 runlevel

    如果沒有指定擴展名,則默認.target

    只有當.target單元文件中的AllowIsolate=yes時,才能使用 isolate 切換;也可以用IgnoreOnIsolate=yes字段來拒絕使用 isolate 切換

    systemctl isolate multi-user.target
    
    cat

    显示單元配置文件的備份文件,包括插入式配置drop-ins,可以完整的看到單元服務的配置。注意這裏打印的依據是磁盤的上內容,如果用戶修改了配置文件(磁盤已修改)但是未執行daemon-reload命令(內存中未更新),那麼該命令显示的配置和實際執行情況有出入

    lfp@legion:~$ systemctl cat mysql.service 
    # /lib/systemd/system/mysql.service
    # MySQL Systemd service file
    
    [Unit]
    Description=MySQL Community Server
    ...
    
    [Install]
    WantedBy=multi-user.target
    
    [Service]
    Type=forking
    ...
    # 這段就显示的是 插入式配置 drop-in 的內容
    # /etc/systemd/system/mysql.service.d/mysql.conf
    # MySQL Systemd service file
    
    [Unit]
    # Description=MySQL Community Server conf
    
    [Service]
    # ExecStartPost=/home/lfp/bin/espeak.sh
    

    單元文件命令

    我的理解

    • systemd 對單元文件自身屬性和內容的管理
    list-unit-files

    列出所有已安裝的單元文件和它們的啟用狀態

    list-units的區別是

    • list-units 僅显示當前已加載到內存中的單元
    • list-unit-files 會讀取單元文件內容,列出所有單元,包括存在於硬盤未加載進內存的單元

    實際測試結果:

    systemctl list-unit-files 显示“348 Unit files listed”

    systemctl list-units –all 显示“405 loaded units listed”

    systemctl list-units 显示 “232 loaded units listed”

    enable

    使某個單元開機自啟動

    這會根據單元文件內容中的[Install]指定的 target 組,創建一個軟鏈接

    lfp@legion:/etc/systemd/system$ vim v2rayL.service
    # 文件內容 [Install] 段
    ......
    [Install]
    WantedBy=multi-user.target
    ......
    
    lfp@legion:/etc/systemd/system$ systemctl is-enabled v2rayL.service 
    disabled
    lfp@legion:/etc/systemd/system$ systemctl enable v2rayL.service 
    # 根據 [Install] 段指定的組,添加軟鏈接
    Created symlink /etc/systemd/system/multi-user.target.wants/v2rayL.service → /etc/systemd/system/v2rayL.service.
    lfp@legion:/etc/systemd/system$ systemctl is-enabled v2rayL.service 
    enabled
    
    disable

    取消某個單元開機自啟動設置,刪除軟鏈接

    這會刪除所有指向該單元文件的軟鏈接,不僅僅是 enable 操作創建的

    reenable

    disable 和 enable 的結合,根據單元文件內容中的 [Install] 段,重置軟鏈接

    is-enabled

    檢查某個單元是否是開機自啟動的(建立的啟動鏈接)

    lfp@legion:~$ systemctl is-enabled mysql
    enabled
    
    get-default

    獲取默認啟動 target,default-target 是指向該 target 的軟鏈接

    set-default

    設置默認啟動 target,同時修改 default-target 指向設定的 target

    systemctl set-default multi-user.target
    

    生命周期管理命令

    daemon-reload

    重新加載所有的單元文件和依賴關係

    對單元文件有修改的時候,需要執行該命令重新加載文件內容

    系統管理命令

    reboot
    systemctl reboot
    

    重啟系統(異步操作)

    it will return after the reboot operation is enqueued, without waiting for it to complete

    poweroff

    關閉系統,切斷電源(異步操作)

    halt

    僅CPU停止工作,其他硬件仍處於開機狀態(異步操作)

    suspend

    暫停系統(異步操作)

    將觸發執行suspend.target

    hibernate

    讓系統進入冬眠狀態(異步操作)

    將觸發執行hibernate.target

    目錄、文件

    /run/systemd/system/

    單元(服務)運行時生成的配置文件所在目錄
    /etc/systemd/system/

    系統或用戶自定義的配置文件,初始化過程中Systemd只執行/etc/systemd/system目錄裏面的配置文件

    /lib/systemd/system/

    軟件安裝時添加的配置文件,類似於 /etc/init.d/

    對於支持 Systemd 的程序,安裝的時候,會自動的在 /lib/systemd/system 目錄添加一個配置文件

    其他目錄都是軟鏈接

    /etc/systemd/system/default.target

    Systemd 執行的第一個單元文件,符號鏈接到默認啟動 target 對應的 .target 單元文件

    優先級

    SysV 的啟動腳本放在/etc/init.d目錄下

    Systemd 的單元文件放在/etc/systemd/system/lib/systemd/system目錄下

    當一個程序在3個目錄下都存在啟動方式時,優先級是/etc/systemd/system --> /lib/systemd/system --> /etc/init.d

    lfp@legion:/etc/init.d$ ll
    -rwxr-xr-x   1 root root  5650 5月  19 22:09 mysql*
    
    lfp@legion:/etc/systemd/system$ ll
    -rw-r--r--  1 root root  511 5月  20 01:42  mysql.service
    
    lfp@legion:/lib/systemd/system$ ll
    -rw-r--r--  1 root root   499 5月  20 01:20  mysql.service
    
    • /etc/systemd/system 裏面的同名service會覆蓋/lib/systemd/system 裏面的

      注意查看文件信息,該同名文件不能是指向 /lib/systemd/system 的軟鏈接

      軟鏈接不會覆蓋而會同步

    • 如果某個程序不存在Systemd 單元文件,那麼會執行/etc/init.d裏面的啟動腳本

    根據啟動過程, /etc/systemd/system/multi-user.target.wants/ 目錄下是很多指向 /lib/systemd/system/目錄的軟鏈接,所以兩個目錄下的單元文件會互相同步。

    如果/etc/systemd/system//etc/systemd/system/multi-user.target.wants/ 同時存在單元文件,測試發現,不管是手動啟動還是開機自啟動,使用的都是 /etc/systemd/system/ 目錄下的service單元文件

    測試
    執行/etc/init.d目錄下的腳本

    mysql 修改 mysql.servicemysql.service.bak 然後通過service mysql restart啟動/etc/init.d/mysql腳本

    下面是啟動后的一些信息

    注:在恢復mysql.service之前,需要先通過service mysql stop 利用/etc/init.d/mysql腳本中的stop結束上面的進程,否則一旦恢復,service mysql stop 執行的操作就不是 /etc/init.d/mysql腳本中的stop,無法結束上面的進程,出現命令無法正常執行的情況

    結束上面的進程,恢復mysql.service,重新啟動

    /etc/systemd/system 覆蓋測試

    未修改前,查看MySQL的狀態

    lfp@legion:~$ service mysql status
    ● mysql.service - MySQL Community Server
    	# 可以發現這裏的 mysql.service 是在 /lib/systemd/system 下面
       Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: en
       Active: active (running) since Sat 2020-04-25 18:34:30 CST; 5h 33min ago
     Main PID: 988 (mysqld)
        Tasks: 28 (limit: 4915)
       CGroup: /system.slice/mysql.service
               └─988 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
    
    4月 25 18:34:30 legion Systemd[1]: Starting MySQL Community Server...
    4月 25 18:34:30 legion Systemd[1]: Started MySQL Community Server.
    

    將 /lib/systemd/system 下面的文件複製到 /etc/systemd/system/ 下面

    sudo cp /lib/systemd/system/mysql.service /etc/systemd/system/
    

    修改 mysql.service

    sudo vim /etc/systemd/system/mysql.service
    

    重啟 mysql.service ,系統提示需要重新加載

    lfp@legion:~$ systemctl restart mysql.service 
    Warning: The Unit file, source configuration file or drop-ins of mysql.service changed on disk. 
    Run 'systemctl daemon-reload' to reload units.
    lfp@legion:~$ systemctl daemon-reload	#  重新加載
    lfp@legion:~$ systemctl restart mysql.service # 重啟
    lfp@legion:~$ systemctl status mysql.service 
    ● mysql.service - MySQL Community Server hahahaha	# 發現這裡是修改之後的,覆蓋了 /lib/systemd/lib 中的
    #                                 這裏也可以看到加載路徑
       Loaded: loaded (/etc/systemd/system/mysql.service; enabled; vendor preset: en
       Active: active (running) since Sun 【2020-04-26】 00:47:02 CST; 5s ago
      Process: 21590 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/m
      Process: 21581 ExecStartPre=/usr/share/mysql/mysql-Systemd-start pre (code=exi
     Main PID: 21592 (mysqld)
        Tasks: 27 (limit: 4915)
       CGroup: /system.slice/mysql.service
               └─21592 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pi
    
    4月 26 00:47:02 legion Systemd[1]: Starting MySQL Community Server hahahaha...
    4月 26 00:47:02 legion Systemd[1
    

    Target

    兩個含義

    1. 系統的某個狀態稱為一個 target(類似於”狀態點”)

    2. 達到某個系統狀態,所需的一個或多個資源(Unit)稱為一個 target(一個 Unit 組)

      1. target是一個抽象的系統資源,不像MySQL有實體

      2. 如果一個target只包含一個Unit,那麼該 target,沒有對應的目錄,指的就是這個 Unit

        例如 hibernate.target 只包含 systemd-hibernate.service一個Unit

        如果一個target包含多個Unit,那麼該target,有對應的 xxx.target.wants 目錄,指的是目錄裏面所有的Unit

        例如 multi-user.target 包含位於/etc/systemd/system/multi-user.target.wants目錄下的多個 Unit

    target也是一個 Target 類型的系統資源,有對應的單元文件 xxx.target

    Systemd 使用 target 來劃分和管理資源(Unit),啟動(激活)某個 xxx.target 單元文件,通過執行該 target 包含的 Unit,使系統達到某種狀態

    對於狀態點的理解:

    例如,執行systemd suspend命令讓系統暫停,會觸發啟動suspend.target,然後執行裏面的systemd-suspend.service Unit,使系統達到一個暫停的狀態

    傳統的init啟動模式裏面,有 RunLevel 的概念,跟 Target 的作用很類似。不同的是,RunLevel 是互斥的,不可能多個 RunLevel 同時啟動,但是多個 Target 可以同時啟動

    啟動 target

    runlevel是 SysV init 初始化系統中的概念,在Systemd初始化系統中使用的是 Target,他們之間的映射關係是

    Runlevel Target 說明
    0 poweroff.target 關閉系統
    1 rescue.target 維護模式
    2,3,4 multi-user.target 多用戶,無圖形系統(命令行界面)
    5 graphical.target 多用戶,圖形化系統(圖形用戶界面)
    6 reboot.target 重啟系統

    啟動過程

    1. 讀入 /boot 目錄下的內核文件

    2. 內核文件加載完之後,開始執行第一個程序/sbin/init 初始化進程,由 Systemd 初始化系統引導,完成相關的初始化工作

    3. Systemd 執行default.target ,獲知設定的啟動 target

      實際上 default.target 是指向設定的啟動 target 的軟鏈接

    4. Systemd 執行啟動 target 對應的單元文件。根據單元文件中定義的依賴關係,傳遞控制權,依次執行其他 target 單元文件,同時啟動每個 target 包含的單元

      對於圖形化界面,默認 target 是 graphical,Systemd 執行位於/lib/systemd/system/ 目錄下的 graphical.target 單元文件,根據 target 單元文件中定義的依賴關係,依次啟動其他 target 單元文件以及各個 target 包含的位於/etc/systemd/system/目錄下的單元

      例如: graphical.target 的依賴關係是

      [Unit]
      Description=Graphical Interface
      Documentation=man:systemd.special(7)
      Requires=multi-user.target #
      Wants=display-manager.service #
      Conflicts=rescue.service rescue.target
      After=multi-user.target rescue.service rescue.target display-manager.service #
      AllowIsolate=yes
      

      因此,依次啟動 multi-user.target –> basic.target –> sysinit.target –> local-fs.target –>local-fs-pre.target –> …

      同時啟動每個 target 包含的位於/etc/systemd/system/目錄下的Unit

      SysV對應的 rc5.d –> /etc/init.d 目錄下的指定的腳本就不會在開機的時候執行了

    查看默認 target

    systemctl get-default

    lfp@legion:~$ runlevel
    N 5
    lfp@legion:~$ systemctl get-default
    graphical.target
    

    修改默認 target

    systemctl set-default [xxx.target]

    # Ubuntu18.04
    # 圖形用戶界面 切換 命令行界面
    sudo systemctl set-default multi-user.target
    # 命令行界面 切換 圖形用戶界面
     systemctl set-default graphical.target
     reboot
     # 命令行界面 想進入 圖形用戶界面(僅進入一次,重啟系統后仍然會進入命令行模式)
     sudo systemctl start lightdm
    

    https://ask.csdn.net/questions/695344

    https://askubuntu.com/a/788465

    其他操作

    修改配置文件

    1. 直接修改/lib/systemd/system目錄下的單元文件

      如果軟件包更新,修改會被丟棄

    2. /lib/systemd/system中的單元文件複製到/etc/systemd/system/

      如果軟件包更新,不會同步更新

    3. /etc/systemd/system/ 中添加配置(推薦)

    添加配置

    步驟:

    1. /etc/systemd/system/ 目錄下新建<單元名>.d目錄
    2. <單元名>.d目錄下,新建<單元名>.conf文件
    3. <單元名>.conf文件中修改配置

    測試:

    1. 創建目錄及文件

      # /mysql.service.d
      lfp@legion:/etc/systemd/system/mysql.service.d$ ls
      mysql.conf
      
    2. 修改配置

      # MySQL Systemd service config file
      # 不需要所有的組,僅添加需要修改的組及選項
      
      [Unit]
      Description=MySQL Community Server config test
      
      [Service]
      ExecStartPost=/home/lfp/bin/espeak.sh
      
    3. 重啟測試

      lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl daemon-reload
      lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl restart mysql.service
      lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl status mysql.service
      lfp@legion:/etc/systemd/system/mysql.service.d$ systemctl status mysql.service
      #                                                                            描述已經被修改
      ● mysql.service - MySQL Community Server config test
         Loaded: loaded (/lib/systemd/system/mysql.service; enabled; vendor preset: enabled)
      # 加入了配置文件
        Drop-In: /etc/systemd/system/mysql.service.d
                 └─mysql.conf
         Active: active (running) since Thu 2020-05-21 20:18:02 CST; 12min ago
      # 新增的動作執行成功
        Process: 4703 ExecStartPost=/home/lfp/bin/espeak.sh (code=exited, status=0/SUCCESS)
        Process: 4672 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid (code=exited, status=0/SUCCESS)
        Process: 4663 ExecStartPre=/usr/share/mysql/mysql-Systemd-start pre (code=exited, status=0/SUCCESS)
       Main PID: 4674 (mysqld)
          Tasks: 27 (limit: 4915)
         CGroup: /system.slice/mysql.service
                 └─4674 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
      
      5月 21 20:18:02 legion espeak.sh[4703]: ALSA lib pcm_route.c:867:(find_matching_chmap) Found no matching channel map
      

    添加開機啟動服務

    1. 添加啟動配置文件
    2. 通過 rc.local文件

    /lib/systemd/rc.local.service

    # 如果存在,就自動添加到 multi-user.target
    # This Unit gets pulled automatically into multi-user.target by
    # Systemd-rc-local-generator if /etc/rc.local is executable.
    [Unit]
    Description=/etc/rc.local Compatibility
    Documentation=man:systemd-rc-local-generator(8)
    ConditionFileIsExecutable=/etc/rc.local
    After=network.target
    
    [Service]
    Type=forking
    ExecStart=/etc/rc.local start
    TimeoutSec=0
    RemainAfterExit=yes
    GuessMainPID=no
    
    

    創建 rc.local 文件,賦予可執行權限,即可添加啟動命令

    sudo touch /etc/rc.local
    chmod 755 /etc/rc.local
    
    lfp@legion:/etc$ vim rc.local
    #!/bin/sh -e
    echo "test rc.local" > /usr/local/rclocal.log
    echo "rc.local `date +%Y-%m-%d-%H:%M:%S`" >/home/lfp/log/rclocal.log
    exit 0
    

    system 工具集

    hostnamectl 主機名管理命令

    hostnamectl
    hostnamectl status

    Show current system hostname and related information

    lfp@legion:/lib/systemd/system$ hostnamectl status
       Static hostname: legion
             Icon name: computer-laptop
               Chassis: laptop
            Machine ID: b28xxxxxxxx2ecafa29e
               Boot ID: 21xxxxxxxxxxxx1d3a47504d
      Operating System: Ubuntu 18.04.4 LTS
                Kernel: Linux 5.3.0-51-generic
          Architecture: x86-64
    

    journalctl 日誌管理命令

    Systemd 統一管理所有 Unit 的啟動日誌。帶來的好處就是,可以只用journalctl一個命令,查看所有日誌(內核日誌和應用日誌)。

    配置文件

    /etc/systemd/journald.conf

    日誌保存目錄

    /var/log/journal/

    默認日誌最大限製為所在文件系統容量的 10%,可通過 /etc/systemd/journald.conf 中的 SystemMaxUse 字段來指定

    該目錄是 systemd 軟件包的一部分。若被刪除,systemd 不會自動創建它,直到下次升級軟件包時重建該目錄。如果該目錄缺失,systemd 會將日誌記錄寫入 /run/systemd/journal。這意味着,系統重啟後日志將丟失。

    journalctl -u [服務名]

    查看指定單元的日誌

    journalctl -b
    • journalctl -b -0 显示本次啟動的信息
    • journalctl -b -1 显示上次啟動的信息
    • journalctl -b -2 显示上上次啟動的信息

    參考

    http://manpages.ubuntu.com/manpages/bionic/en/man1/systemctl.1.html

    http://manpages.ubuntu.com/manpages/bionic/en/man5/systemd.unit.5.html

    https://www.cnblogs.com/yingsong/p/6012180.html

    https://www.cnblogs.com/sparkdev/p/8472711.html

    http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html

    http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-part-two.html

    https://linoxide.com/linux-how-to/systemd-boot-process/

    https://cloud.tencent.com/developer/article/1516125

    https://www.cnblogs.com/sparkdev/p/8472711.html

    https://www.ibm.com/developerworks/cn/linux/1407_liuming_init3/index.html?ca=drs-

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 面試官:換人!他連哈希扣的都不懂

    面試官:換人!他連哈希扣的都不懂

    前言

    相信你面試的時候,肯定被問過 hashCode 和 equals 相關的問題 。如:

    • hashCode 是什麼?它是怎麼得來的?有什麼用?
    • 經典題,equals 和 == 有什麼區別?
    • 為什麼要重寫 equals 和 hashCode ?
    • 重寫了 equals ,就必須要重寫 hashCode 嗎?為什麼?
    • hashCode 相等時,equals 一定相等嗎?反過來呢?

    好的,上面就是靈魂拷問環節。其實,這些問題仔細想一下也不難,主要是平時我們很少去思考它。

    正文

    下面就按照上邊的問題順序,一個一個剖析它。扒開 hashCode 的神秘面紗。

    什麼是 hashCode?

    我們通常說的 hashCode 其實就是一個經過哈希運算之後的整型值。而這個哈希運算的算法,在 Object 類中就是通過一個本地方法 hashCode() 來實現的(HashMap 中還會有一些其它的運算)。

    public native int hashCode();
    

    可以看到它是一個本地方法。那麼,想要了解這個方法到底是用來幹嘛的,最直接有效的方法就是,去看它的源碼註釋。

    下邊我就用我蹩腳的英文翻譯一下它的意思。。。

    返回當前對象的一個哈希值。這個方法用於支持一些哈希表,例如 HashMap 。

    通常來講,它有如下一些約定:

    • 若對象的信息沒有被修改,那麼,在一個程序的執行期間,對於相同的對象,不管調用多少次 hashCode 方法,都應該返回相同的值。當然,在相同程序的不同執行期間,不需要保持結果一致。
    • 若兩個對象的 equals 方法返回值相同,那麼,調用它們各自的 hashCode 方法時,也必須返回相同的結果。(ps: 這句話解答了上邊的一些問題,後面會用例子來證明這一點)
    • 當兩個對象的 equals 方法返回值不同時,那麼它們的 hashCode 方法不用保證必須返回不同的值。但是,我們應該知道,在這種情況下,我們最好也設計成 hashCode 返回不同的值。因為,這樣做有助於提高哈希表的性能。

    在實際情況下,Object 類的 hashCode 方法在不同的對象中確實返回了不同的哈希值。這通常是通過把對象的內部地址轉換為一個整數來實現的。

    ps: 這裏說的內部地址就是指物理地址,也就是內存地址。需要注意的是,雖然 hashCode 值是依據它的內存地址而得來的。但是,不能說 hashCode 就代表對象的內存地址,實際上,hashCode 地址是存放在哈希表中的。

    上邊的源碼註釋真可謂是句句珠璣,把 hashCode 方法解釋的淋漓盡致。一會兒我通過一個案例說明,就能明白我為什麼這樣說了。

    什麼是哈希表?

    上文中提到了哈希表。什麼是哈希表呢?我們直接看百度百科的解釋。

    用一張圖來表示它們的關係。

    左邊一列就是一些關鍵碼(key),通過哈希函數,它們都會得到一個固定的值,分別對應右邊一列的某個值。右邊的這一列就可以認為是一張哈希表。

    而且,我們會發現,有可能有些 key 不同,但是它們對應的哈希值卻是一樣的,例如 aa,bb 都指向 1001 。但是,一定不會出現同一個 key 指向不同的值。

    這也非常好理解,因為哈希表就是用來查找 key 的哈希地址的。在 key 確定的情況下,通過哈希函數計算出來的 哈希地址,一定也是確定的。如圖中的 dd 已經確定在 1002 位置了,那麼就不可能再佔據 1003 位置。

    思考一下,如果有另外一個元素 ee 來了,它的哈希地址也落在 1002 位置,怎麼辦呢?

    hashCode 有什麼用?

    其實,上圖就已經可以說明一些問題了。我們通過一個 key 計算出它的 hashCode 值,就可以唯一確定它在哈希表中的位置。這樣,在查詢時,就可以直接定位到當前元素,提高查詢效率。

    現在我們假設有這樣一個場景。我們需要在內存中的一塊兒區域存放 10000 個不同的元素(以aa,bb,cc,dd 等為例)。那怎麼實現不同的元素插入,相同的元素覆蓋呢?

    我們最容易想到的方法就是,每當存一個新元素時,就遍歷一遍已經存在的元素,看有沒有相同的。這樣雖然也是可以實現的,但是,如果已經存在了 9000 個元素,你就需要去遍歷一下這 9000 個元素。很明顯,這樣的效率是非常低下的。

    我們轉換一種思路,還是以上圖為例。若來了一個新元素 ff,首先去計算它的 hashCode 值,得出為 1003 。發現此處還沒有元素,則直接把這個新元素 ff 放到此位置。

    然後,ee 來了,通過計算哈希值得到 1002 。此時,發現 1002 位置已經存在一個元素了。那麼,通過 equals 方法比較它們是否相等,發現只有一個 dd 元素,很明顯和 ee 不相等。那麼,就把 ee 元素放到 dd 元素的後邊(可以用鏈表形式存放)。

    我們會發現,當有新元素來的時候,先去計算它們的哈希值,再去確定存放的位置,這樣就可以減少比較的次數。如 ff 不需要比較, ee 只需要和 dd 比較一次。

    當元素越來越多的時候,新元素也只需要和當前哈希值相同的位置上,已經存在的元素進行比較。而不需要和其他哈希值不同的位置上的元素進行比較。這樣就大大減少了元素的比較次數。

    圖中為了方便,畫的哈希表比較小。現在假設,這個哈希表非常的大,例如有這麼非常多個位置,從 1001 ~ 9999。那麼,新元素插入的時候,有很大概率會插入到一個還沒有元素存在的位置上,這樣就不需要比較了,效率非常高。但是,我們會發現這樣也有一個弊端,就是哈希表所佔的內存空間就會變大。因此,這是一個權衡的過程。

    有心的同學可能已經發現了。我去,上邊的這個做法好熟悉啊。沒錯,它就是大名鼎鼎的 HashMap 底層實現的思想。對 HashMap 還不了解的,趕緊看這篇文章理一下思路。HashMap 底層實現原理及源碼分析

    所以,hashCode 有什麼用。很明顯,提高了查詢,插入元素的效率呀。

    equals 和 == 有什麼區別?

    這是萬年不變,經久不衰的經典面試題了。讓我油然想起,當初為了面試,背誦過的面經了,簡直是一把心酸一把淚。現在還能記得這道題的標準答案:equals 比較的是內容, == 比較的是地址。

    當時,真的就只是背答案,知其然而不知其所以然。再往下問,為什麼要重寫 equals ,就懵逼了。

    首先,我們應該知道 equals 是定義在所有類的父類 Object 中的。

     public boolean equals(Object obj) {
         return (this == obj);
     }
    

    可以看到,它的默認實現,就是 == ,這是用來比較內存地址的。所以,如果一個對象的 equals 不重寫的話,和 == 的效果是一樣的。

    我們知道,當創建兩個普通對象時,一般情況下,它們所對應的內存地址是不一樣的。例如,我定義一個 User 類。

    public class User {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public User() {
    
        }
    }
    
    public class TestHashCode {
        public static void main(String[] args) {
            User user1 = new User("zhangsan", 20);
            User user2 = new User("lisi", 18); 
    
            System.out.println(user1 == user2);
            System.out.println(user1.equals(user2));
        }
    }
    // 結果: false	false
    

    很明顯,zhangsan 和 lisi 是兩個人,兩個不同的對象。因此,它們所對應的內存地址不同,而且內容也不相等。

    注意,這裏我還沒有對 User 重寫 equals,實際此時 equals 使用的是父類 Object 的方法,返回的肯定是不相等的。因此,為了更好地說明問題,我僅把第二行代碼修改如下:

    //User user2 = new User("lisi", 18);
    User user2 = new User("zhangsan", 20);
    

    讓 user1 和 user2 的內容相同,都是 zhangsan,20歲。按我們的理解,這雖然是兩個對象,但是應該是指的同一個人,都是張三。但是,打印結果,如下:

    這有悖於我們的認知,明明是同一個人,為什麼 equals 返回的卻不相等呢。因此,此時我們就需要把 User 類中的 equals 方法重寫,以達到我們的目的。在 User 中添加如下代碼(使用 idea 自動生成代碼):

    public class User {
        ... //省略已知代碼
            
        @Override
        public boolean equals(Object o) {
            //若兩個對象的內存地址相同,則說明指向的是同一個對象,故內容一定相同。
            if (this == o) return true;
            //類都不是同一個,更別談相等了
            if (o == null || getClass() != o.getClass()) return false;
            User user = (User) o;
            //比較兩個對象中的所有屬性,即name和age都必須相同,才可認為兩個對象相等
            return age == user.age &&
                    Objects.equals(name, user.name);
        }
       
    }
    //打印結果:  false 	true
    

    再次執行程序,我們會發現此時 equals 返回 true ,這才是我們想要的。

    因此,當我們使用自定義對象時。如果需要讓兩個對象的內容相同時,equals 返回 true,則需要重寫 equals 方法。

    為什麼要重寫 equals 和 hashCode ?

    在上邊的案例中,其實我們已經說明了為什麼要去重寫 equals 。因為,在對象內容相同的情況下,我們需要讓對象相等。因此,不能用 Object 類的默認實現,只去比較內存地址,這樣是不合理的。

    那 hashCode 為什麼要重寫呢? 這就涉及到集合,如 Map 和 Set (底層其實也是 Map)了。

    我們以 HashMap JDK1.8的源碼來看,如 put 方法。

    我們會發現,代碼中會多次進行 hash 值的比較,只有當哈希值相等時,才會去比較 equals 方法。當 hashCode 和 equals 都相同時,才會覆蓋元素。get 方法也是如此(先比較哈希值,再比較equals),

    只有 hashCode 和 equals 都相等時,才認為是同一個元素,找到並返回此元素,否則返回 null。

    這也對應 “hashCode 有什麼用?”這一小節。 重寫 equals 和 hashCode 的目的,就是為了方便哈希表這樣的結構快速的查詢和插入。如果不重寫,則無法比較元素,甚至造成元素位置錯亂。

    重寫了 equals ,就必須要重寫 hashCode 嗎?

    答案是肯定的。首先,在上邊的 JDK 源碼註釋中第第二點,我們就會發現這句說明。其次,我們嘗試重寫 equals ,而不重寫 hashCode 看會發生什麼現象。

    public class TestHashCode {
        public static void main(String[] args) {
            User user1 = new User("zhangsan", 20);
            User user2 = new User("zhangsan", 20);
    
            HashMap<User, Integer> map = new HashMap<>();
            map.put(user1,90);
            System.out.println(map.get(user2));
        }
    }
    // 打印結果: null
    

    對於代碼中的 user1 和 user2 兩個對象來說,我們認為他是同一個人張三。定義一個 map ,key 存儲 User 對象, value 存儲他的學習成績。

    當把 user1 對象作為 key ,成績 90 作為 value 存儲到 map 中時,我們肯定希望,用 key 為 user2 來取值時,得到的結果是 90 。但是,結果卻大失所望,得到了 null 。

    這是因為,我們自定義的 User 類,雖然重寫了 equals ,但是沒有重寫 hashCode 。當 user1 放到 map 中時,計算出來的哈希值和用 user2 去取值時計算的哈希值不相等。因此,equals 方法都沒有比較的機會。認為他們是不同的元素。然而,其實,我們應該認為 user1 和 user2 是相同的元素的。

    用圖來說明就是,user1 和 user2 存放在了 HashMap 中不同的桶裡邊,導致查詢不到目標元素。

    因此,當我們用自定義類來作為 HashMap 的 key 時,必須要重寫 hashCode 和 equals 。否則,會得到我們不想要的結果。

    這也是為什麼,我們平時都喜歡用 String 字符串來作為 key 的原因。 因為, String 類默認就幫我們實現了 equals 和 hashCode 方法的重寫。如下,

    // String.java
    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            //從前向後依次比較字符串中的每個字符
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
    
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
    		//把字符串中的每個字符都取出來,參与運算
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            //把計算出來的最終值,存放在hash變量中。
            hash = h;
        }
        return h;
    }
    

    重寫 equals 時,可以使用 idea 提供的自動代碼,也可以自己手動實現。

    public class User {
        ... //省略已知代碼
            
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
       
    }
    //此時,map.get(user2) 可以得到 90 的正確值
    

    在重寫了 hashCode 后,使用自定義對象作為 key 時,還需要注意一點,不要在使用過程中,改變對象的內容,這樣會導致 hashCode 值發生改變,同樣得不到正確的結果。如下,

    public class TestHashCode {
        public static void main(String[] args) {
            User user = new User("zhangsan", 20);
    
            HashMap<User, Integer> map = new HashMap<>();
            map.put(user,90);
            System.out.println(map.get(user));
            user.setAge(18); //把對象的年齡修改為18
            System.out.println(map.get(user));
        }
    }
    // 打印結果:
    // 90
    // null
    

    會發現,修改后,拿到的值是 null 。這也是,hashCode 源碼註釋中的第一點說明的,hashCode 值不變的前提是,對象的信息沒有被修改。若被修改,則有可能導致 hashCode 值改變。

    此時,有沒有聯想到其他一些問題。比如,為什麼 String 類要設計成不可以變的呢?這裏用 String 作為 HashMap 的 key 時,可以算作一個原因。你肯定不希望,放進去的時候還好好的,取出來的時候,卻找不到元素了吧。

    String 類內部會有一個變量(hash)來緩存字符串的 hashCode 值。只有字符串不可變,才可以保證哈希值不變。

    hashCode 相等時,equals 一定相等嗎?

    很顯然不是的。在 HashMap 的源碼中,我們就能看到,當 hashCode 相等時(產生哈希碰撞),還需要比較它們的 equals ,才可以確定是否是同一個對象。因此,hashCode 相等時, equals 不一定相等 。

    反過來,equals 相等的話, hashCode 一定相等嗎? 那必須的。equals 都相等了,那說明在 HashMap 中認為它們是同一個元素,所以 hashCode 值必須也要保證相等。

    結論:

    • hashCode 相等,equals 不一定相等。
    • hashCode 不等,equals 一定不等。
    • equals 相等, hashCode 一定相等。
    • equals 不等, hashCode 不一定不等。

    關於最後這一點,就是 hashCode 源碼註釋中提到的第三點。當 equals 不等時,不用必須保證它們的 hashCode 也不相等。但是為了提高哈希表的效率,最好設計成不等。

    因為,我們既然知道它們不相等了,那麼當 hashCode 設計成不等時。只要比較 hashCode 不相等,我們就可以直接返回 null,而不必再去比較 equals 了。這樣,就減少了比較的次數,無疑提高了效率。

    結尾

    以上就是 hashCode 和 equals 相關的一些問題。相信已經可以解答你心中的疑惑了,也可以和面試官侃侃而談。再也不用擔心,面試官說換人了。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

  • C++ Primer Plus(三)

    完整閱讀C++ Primer Plus 

      系統重新學習C++語言部分,記錄重要但易被忽略的,關鍵但易被遺忘的。

     

    使用類

      1、不能重載的運算符

     1 sizeof       sizeof運算符
     2 .            成員運算符
     3 .*           成員指針運算符
     4 ::           作用域解析運算符
     5 ?:           條件運算符
     6 typeid       一個RTTI運算符
     7 const_cast         強制類型轉換運算符
     8 dynamic_cast       強制類型轉換運算符
     9 reinterpret_cast   強制類型轉換運算符
    10 static_cast       強制類型轉換運算符

      2、只能通過成員函數重載的運算符

    1 =         賦值運算符
    2 ()        函數調用運算符
    3 []        下標運算符
    4 ->        通過指針訪問類成員的運算符

      3、關於類的類型轉換函數,C++11支持對其使用explicit關鍵字,使其無法進行隱式類型轉換。

      4、對於定義了一個以上的轉換函數的類,編譯器在某些情況下(如將一個對象直接賦值給一個基本類型,或用cout輸出時)無法確定應該使用哪一個轉換函數(進行隱式類型轉換),因此將出現二義性錯誤,但只有一個轉換函數時,編譯器只能選擇這一個,因此不會出錯。

     

    類和動態內存分配

      5、將新對象显示地初始化為現有對象時將調用拷貝構造函數,默認的拷貝構造函數將除靜態成員以外的所有成員按值賦值。

    1 String a(b);
    2 String a = b;
    3 String a = String(b);
    4 String * a = new String(b);

      將已有的對象賦值給另一個已有的對象時,會調用賦值構造函數。

      6、靜態成員函數不與特定的對象關聯,因此只能使用靜態數據成員(單例模式)。

      7、對於使用定位new運算符創建的對象,應顯式地調用其析構函數,需要注意的是,在析構時,對象的析構順序應該與創建順序相反,因為晚創建的對象可能依賴於早創建的對象,另外,只有當所有對象被銷毀后,才能釋放存儲這些對象地緩衝區。

      8、只有構造函數可以使用初始化列表語法,對於const類成員(C++11之前)和聲明為引用的類成員,必須使用這種語法,因為它們只能在被創建時初始化。

     

    類繼承

      9、 公有繼承是最常用的繼承方式,它建立一種is-a關係,即派生類對象也是一個基類對象,可以對基類對象執行的任何操作,也可以對派生類對象執行。公有繼承不建立has-a關係;公有繼承不建立is-like-a關係;公有繼承不建立is-implemented-as-a(作為……來實現)關係;公有繼承不建立uses-a關係。在C++中,完全可以使用公有繼承來實現has-a、is-implemented-as-a或use-a關係,然而這樣做通常會導致編程方面的問題,因此,還是堅持使用is-a關係吧。

      10、 在基類的方法中使用關鍵字virtual可使該方法在基類已經所有派生類(包括從派生類派生出來的類)中是虛的,也就是說只要函數名相同,只需要在基類中聲明為虛函數,那它的派生類中,包括派生派生類中的這個函數都是虛函數,但為了可讀性,一般派生類中的虛函數也用virtual聲明。

      11、如果重新定義繼承的方法,應確保與原來的原型完全相同,但如果返回類型是基類引用或指針,則可以修改為指向派生類的引用或指針,這種特性被稱為返回類型協變,因為允許返回類型隨類類型的變化而變化。

      12、如果基類聲明被重載了,則應在派生類中重新定義所有的基類版本,如果只在派生類中只定義了一個版本,則另外的版本將被隱藏。

      13、C++允許純虛函數有定義,但不能在類內定義,可以在實現文件中定義。

      14、當基類和派生類都為至少一個成員採用了動態內存分配時,派生類的析構函數,拷貝構造函數,賦值構造函數都必須使用相應的基類方法來處理基類元素。對於析構函數,這是自動完成的;對於拷貝構造函數,是通過初始化列表中調用積累的拷貝構造函數完成的;對於賦值構造函數是通過使用作用域解析運算符显示地調用基類的賦值構造函數完成的。

      15、當派生類的友元函數需要訪問基類中的非公有成員時,做法是在派生類的友元函數中將派生類的引用強制類型轉換為基類的引用。

     

    C++中的代碼重用

      16、當類的初始化列表包含多個項目時,這些項目的初始化順序為聲明它們的順序,而不是他們在初始化列表中的順序,如果代碼使用一個成員的值作為另一個成員初始化表達式的一部分時,初始化順序就需要引起注意。

      17、在繼承時,private是默認值,因此忽略訪問限定符也將導致私有繼承。

      18、在私有繼承時,訪問基類方法,需要使用類名加作用域解析運算符訪問;訪問基類對象(例如將基類對象當作返回值時),可以將派生類強制類型轉換為基類;訪問基類友元函數時,因為友元函數不屬於成員函數,因此不能顯式地限定函數名去訪問,可以通過顯式地轉換為基類來調用正確的函數。

      19、通常,應該使用包含來建立has-a關係,如果新類需要訪問原有類的保護成員,或需要重新定義虛函數,則應使用私有繼承。

      20、對於指向對象的類或引用中的隱式向上轉換,公有繼承直接支持,保護繼承只在派生類中支持,私有繼承不支持。

      21、如果要使私有繼承的基類中的私有函數可以在派生類外訪問,可以聲明一個公有函數,再去調用基類的私有函數,另外還可以使用using聲明:

    1 class A:private B
    2 {
    3 public:
    4     using B:foo; // 只需要有函數簽名即可,所有重載版本都可以使用
    5 }

      另一種老式的方法是將基類方法名放在派生類的共有部分。

      22、在多重繼承中,如果出現了菱形繼承,頂端的基類應該使用虛繼承,防止底端的派生類包含兩份基類,同時,在構造函數的初始化列表裡應該顯式地調用頂端基類的構造函數,對於虛基類必須這樣做,否則將使用虛基類的默認構造函數,並且此時的虛基類無法通過中間的派生類去完成構造,但對於非虛基類,這是非法的。

      23、在混合使用虛基類和非虛基類,類通過多條虛途徑和非虛途徑繼承某個特定的基類時,該類將包含,一個表示所有的虛途徑即基類子對象和分別表示各條非虛途徑的多個基類子對象。

      24、使用非虛基類時,二義性的規則很簡單,只要類從不同類那裡繼承了同名的成員,使用時沒有用類名限定,則一定會導致二義性,但虛基類時不一定會導致二義性,如果某個名稱優先於其他名稱,則使用它。優先的規則是,派生類中的名稱優先於直接或間接祖先類中的相同名稱。

      25、有間接虛基類的派生類包含直接調用間接基類構造函數的構造函數,這對於間接非虛基類是非法的。

      26、 在類模板中,模板代碼不能修改參數的值,也不能使用參數得地址,在實例化時,用作表達式參數的值必須是常量表達式。

      27、使用關鍵字template並指出所需類型來聲明類時,編譯器將生成類聲明的顯式實例化,聲明必須位於模板定義所在的命名空間中。

      28、C++允許部分具體化:

    1 template <class T1, class T2> class Pair{};  // 一般版本
    2 template <class T1> class Pair<T1, int>{};    // 部分顯式具體化版本

      template后的<>中是沒有被具體化的參數,如果指定所有的類型,template后的<>將為空,這會導致顯式具體化。

      29、如果有多個版本可以選擇,編譯器將選擇具體化最高的版本,部分具體化特性使得能夠設置各種限制。

    1 template<T> class Feeb{};
    2 template<T*> class Feeb{}; // 也可以為指針提供特殊版本來部分具體化
    3 
    4 template<class T1, class T2, class T3> class Trio{}; //一般版本
    5 template<class T1, class T2> class Trio<T1, T2, T2>{}; // 使用T2設置T3
    6 template<class T1> class Trio<T1, T1*, T1*>{}; // 使用T1的指針來設置T2和T3

      30、較老的編譯器不支持模板成員,而另一些編譯器支持模板成員,但是不支持在類外面的定義。如果支持類外定義,則必須通過作用域解析運算符指出是哪個類的成員,並且使用嵌套模板的聲明方式。

    1 template<typename T>
    2 template<typename V>  // 嵌套方式  

      31、 對於模板類的非模板友元函數,它不是通過對象調用的,因為它不是成員函數,它可以訪問全局對象,可以使用全局指針訪問非全局對象,可以創建自己的對象,可以訪問獨立於對象的模板類靜態數據成員。

      32、在聲明模板類的約束模板友元函數(友元函數也是模板函數)時,需要在類中聲明具體化的友元函數,同時也需要在類外聲明並且給出友元函數的定義。

      33、除了使用typedef對模板進行重命名,C++11新增了別名

    1 template<typename T>
    2 using arrtype = std::array<T,12>;
    3 arrtype<int> days;

      這種語法也適用於非模板,用於非模板時,它和typedef等價。

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    新北清潔公司,居家、辦公、裝潢細清專業服務

    ※教你寫出一流的銷售文案?