0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為何需要CMWQ?CMWQ如何解決問題的呢?

Linux閱碼場(chǎng) ? 來源:未知 ? 作者:李倩 ? 2018-08-20 14:47 ? 次閱讀

一、前言

一種新的機(jī)制出現(xiàn)的原因往往是為了解決實(shí)際的問題,雖然linux kernel中已經(jīng)提供了workqueue的機(jī)制,那么為何還要引入cmwq呢?也就是說:舊的workqueue機(jī)制存在什么樣的問題?在新的cmwq又是如何解決這些問題的呢?它接口是如何呈現(xiàn)的呢(驅(qū)動(dòng)工程師最關(guān)心這個(gè)了)?如何兼容舊的驅(qū)動(dòng)呢?本文希望可以解開這些謎題。

本文的代碼來自linux kernel 4.0。

二、為何需要CMWQ?

內(nèi)核中很多場(chǎng)景需要異步執(zhí)行環(huán)境(在驅(qū)動(dòng)中尤其常見),這時(shí)候,我們需要定義一個(gè)work(執(zhí)行哪一個(gè)函數(shù))并掛入workqueue。處理該work的線程叫做worker,不斷的處理隊(duì)列中的work,當(dāng)處理完畢后則休眠,隊(duì)列中有work的時(shí)候就醒來處理,如此周而復(fù)始。一切看起來比較完美,問題出在哪里呢?

(1)內(nèi)核線程數(shù)量太多。如果沒有足夠的內(nèi)核知識(shí),程序員有可能會(huì)錯(cuò)誤的使用workqueue機(jī)制,從而導(dǎo)致這個(gè)機(jī)制被玩壞。例如明明可以使用default workqueue,偏偏自己創(chuàng)建屬于自己的workqueue,這樣一來,對(duì)于那些比較大型的系統(tǒng)(CPU個(gè)數(shù)比較多),很可能內(nèi)核啟動(dòng)結(jié)束后就耗盡了PID space(default最大值是65535),這種情況下,你讓user space的程序情何以堪?雖然default最大值是可以修改的,從而擴(kuò)大PID space來解決這個(gè)問題,不過系統(tǒng)太多的task會(huì)對(duì)整體performance造成負(fù)面影響。

(2)盡管消耗了很多資源,但是并發(fā)性如何呢?我們先看single threaded的workqueue,這種情況完全沒有并發(fā)的概念,任何的work都是排隊(duì)執(zhí)行,如果正在執(zhí)行的work很慢,例如4~5秒的時(shí)間,那么隊(duì)列中的其他work除了等待別無選擇。multi threaded(更準(zhǔn)確的是per-CPU threaded)情況當(dāng)然會(huì)好一些(畢竟多消耗了資源),但是對(duì)并發(fā)仍然處理的不是很好。對(duì)于multi threaded workqueue,雖然創(chuàng)建了thread pool,但是thread pool的數(shù)目是固定的:每個(gè)oneline的cpu上運(yùn)行一個(gè),而且是嚴(yán)格的綁定關(guān)系。也就是說本來線程池是一個(gè)很好的概念,但是傳統(tǒng)workqueue上的線程池(或者叫做worker pool)卻分割了每個(gè)線程,線程之間不能互通有無。例如cpu0上的worker thread由于處理work而進(jìn)入阻塞狀態(tài),那么該worker thread處理的work queue中的其他work都阻塞住,不能轉(zhuǎn)移到其他cpu上的worker thread去,更有甚者,cpu0上隨后掛入的work也接受同樣的命運(yùn)(在某個(gè)cpu上schedule的work一定會(huì)運(yùn)行在那個(gè)cpu上),不能去其他空閑的worker thread上執(zhí)行。由于不能提供很好的并發(fā)性,有些內(nèi)核模塊(fscache)甚至自己創(chuàng)建了thread pool(slow work也曾經(jīng)短暫的出現(xiàn)在kernel中)。

(3)dead lock問題。我們舉一個(gè)簡(jiǎn)單的例子:我們知道,系統(tǒng)有default workqueue,如果沒有特別需求,驅(qū)動(dòng)工程師都喜歡用這個(gè)workqueue。我們的驅(qū)動(dòng)模塊在處理release(userspace close該設(shè)備)函數(shù)的時(shí)候,由于使用了workqueue,那么一般會(huì)flush整個(gè)workqueue,以便確保本driver的所有事宜都已經(jīng)處理完畢(在close的時(shí)候很有可能有pending的work,因此要flush),大概的代碼如下:

flush work是一個(gè)長期過程,因此很有可能被調(diào)度出去,這樣調(diào)用close的進(jìn)程被阻塞,等到keventd_wq這個(gè)內(nèi)核線程組完成flush操作后就會(huì)wakeup該進(jìn)程。但是這個(gè)default workqueue使用很廣,其他的模塊也可能會(huì)schedule work到該workqueue中,并且如果這些模塊的work也需要獲取鎖A,那么就會(huì)deadlock(keventd_wq阻塞,再也無法喚醒等待flush的進(jìn)程)。解決這個(gè)問題的方法是創(chuàng)建多個(gè)workqueue,但是這樣又回到了內(nèi)核線程數(shù)量大多的問題上來。

我們?cè)倏匆粋€(gè)例子:假設(shè)某個(gè)驅(qū)動(dòng)模塊比較復(fù)雜,使用了兩個(gè)work struct,分別是A和B,如果work A依賴 work B的執(zhí)行結(jié)果,那么,如果這兩個(gè)work都schedule到一個(gè)worker thread的時(shí)候就出現(xiàn)問題,由于worker thread不能并發(fā)的執(zhí)行work A和work B,因此該驅(qū)動(dòng)模塊會(huì)死鎖。Multi threaded workqueue能減輕這個(gè)問題,但是無法解決該問題,畢竟work A和work B還是有機(jī)會(huì)調(diào)度到一個(gè)cpu上執(zhí)行。造成這些問題的根本原因是眾多的work競(jìng)爭(zhēng)一個(gè)執(zhí)行上下文導(dǎo)致的。

(4)二元化的線程池機(jī)制?;旧蟱orkqueue也是thread pool的一種,但是創(chuàng)建的線程數(shù)目是二元化的設(shè)定:要么是1,要么是number of CPU,但是,有些場(chǎng)景中,創(chuàng)建number of CPU太多,而創(chuàng)建一個(gè)線程又太少,這時(shí)候,勉強(qiáng)使用了single threaded workqueue,但是不得不接受串行處理work,使用multi threaded workqueue吧,占用資源太多。二元化的線程池機(jī)制讓用戶無所適從。

三、CMWQ如何解決問題的呢?

1、設(shè)計(jì)原則。在進(jìn)行CMWQ的時(shí)候遵循下面兩個(gè)原則:

(1)和舊的workqueue接口兼容。

(2)明確的劃分了workqueue的前端接口和后端實(shí)現(xiàn)機(jī)制。CMWQ的整體架構(gòu)如下:

對(duì)于workqueue的用戶而言,前端的操作包括二種,一個(gè)是創(chuàng)建workqueue??梢赃x擇創(chuàng)建自己的workqueue,當(dāng)然也可以不創(chuàng)建而是使用系統(tǒng)缺省的workqueue。另外一個(gè)操作就是將指定的work添加到workqueue。在舊的workqueue機(jī)制中,workqueue和worker thread是密切聯(lián)系的概念,對(duì)于single workqueue,創(chuàng)建一個(gè)系統(tǒng)范圍的worker thread,對(duì)于multi workqueue,創(chuàng)建per-CPU的worker thread,一切都是固定死的。針對(duì)這樣的設(shè)計(jì),我們可以進(jìn)一步思考其合理性。workqueue用戶的需求就是一個(gè)異步執(zhí)行的環(huán)境,把創(chuàng)建workqueue和創(chuàng)建worker thread綁定起來大大限定了資源的使用,其實(shí)具體后臺(tái)是如何處理work,是否否啟動(dòng)了多個(gè)thread,如何管理多個(gè)線程之間的協(xié)調(diào),workqueue的用戶并不關(guān)心。

基于這樣的思考,在CMWQ中,將這種固定的關(guān)系被打破,提出了worker pool這樣的概念(其實(shí)就是一種thread pool的概念),也就是說,系統(tǒng)中存在若干worker pool,不和特定的workqueue關(guān)聯(lián),而是所有的workqueue共享。用戶可以創(chuàng)建workqueue(不創(chuàng)建worker pool)并通過flag來約束掛入該workqueue上work的處理方式。workqueue會(huì)根據(jù)其flag將work交付給系統(tǒng)中某個(gè)worker pool處理。例如如果該workqueue是bounded類型并且設(shè)定了high priority,那么掛入該workqueue的work將由per cpu的highpri worker-pool來處理。

讓所有的workqueue共享系統(tǒng)中的worker pool,即減少了資源的浪費(fèi)(沒有創(chuàng)建那么多的kernel thread),又保證了靈活的并發(fā)性(worker pool會(huì)根據(jù)情況靈活的創(chuàng)建thread來處理work)。

3、如何解決線程數(shù)目過多的問題?

在CMWQ中,用戶可以根據(jù)自己的需求創(chuàng)建workqueue,但是已經(jīng)和后端的線程池是否創(chuàng)建worker線程無關(guān)了,是否創(chuàng)建新的work線程是由worker線程池來管理。系統(tǒng)中的線程池包括兩種:

(1)和特定CPU綁定的線程池。這種線程池有兩種,一種叫做normal thread pool,另外一種叫做high priority thread pool,分別用來管理普通的worker thread和高優(yōu)先級(jí)的worker thread,而這兩種thread分別用來處理普通的和高優(yōu)先級(jí)的work。這種類型的線程池?cái)?shù)目是固定的,和系統(tǒng)中cpu的數(shù)目相關(guān),如果系統(tǒng)有n個(gè)cpu,如果都是online的,那么會(huì)創(chuàng)建2n個(gè)線程池。

(2)unbound 線程池,可以運(yùn)行在任意的cpu上。這種thread pool是動(dòng)態(tài)創(chuàng)建的,是和thread pool的屬性相關(guān),包括該thread pool創(chuàng)建worker thread的優(yōu)先級(jí)(nice value),可以運(yùn)行的cpu鏈表等。如果系統(tǒng)中已經(jīng)有了相同屬性的thread pool,那么不需要?jiǎng)?chuàng)建新的線程池,否則需要?jiǎng)?chuàng)建。

OK,上面講了線程池的創(chuàng)建,了解到創(chuàng)建workqueue和創(chuàng)建worker thread這兩個(gè)事件已經(jīng)解除關(guān)聯(lián),用戶創(chuàng)建workqueue僅僅是選擇一個(gè)或者多個(gè)線程池而已,對(duì)于bound thread pool,每個(gè)cpu有兩個(gè)thread pool,關(guān)系是固定的,對(duì)于unbound thread pool,有可能根據(jù)屬性動(dòng)態(tài)創(chuàng)建thread pool。那么worker thread pool如何創(chuàng)建worker thread呢?是否會(huì)數(shù)目過多呢?

缺省情況下,創(chuàng)建thread pool的時(shí)候會(huì)創(chuàng)建一個(gè)worker thread來處理work,隨著work的提交以及work的執(zhí)行情況,thread pool會(huì)動(dòng)態(tài)創(chuàng)建worker thread。具體創(chuàng)建worker thread的策略為何?本質(zhì)上這是一個(gè)需要在并發(fā)性和系統(tǒng)資源消耗上進(jìn)行平衡的問題,CMWQ使用了一個(gè)非常簡(jiǎn)單的策略:當(dāng)thread pool中處于運(yùn)行狀態(tài)的worker thread等于0,并且有需要處理的work的時(shí)候,thread pool就會(huì)創(chuàng)建新的worker線程。當(dāng)worker線程處于idle的時(shí)候,不會(huì)立刻銷毀它,而是保持一段時(shí)間,如果這時(shí)候有創(chuàng)建新的worker的需求的時(shí)候,那么直接wakeup idle的worker即可。一段時(shí)間過去仍然沒有事情處理,那么該worker thread會(huì)被銷毀。

4、如何解決并發(fā)問題?

我們用某個(gè)cpu上的bound workqueue來描述該問題。假設(shè)有A B C D四個(gè)work在該cpu上運(yùn)行,缺省的情況下,thread pool會(huì)創(chuàng)建一個(gè)worker來處理這四個(gè)work。在舊的workqueue中,A B C D四個(gè)work毫無疑問是串行在cpu上執(zhí)行,假設(shè)B work阻塞了,那么C D都是無法執(zhí)行下去,一直要等到B解除阻塞并執(zhí)行完畢。

對(duì)于CMWQ,當(dāng)B work阻塞了,thread pool可以感知到這一事件,這時(shí)候它會(huì)創(chuàng)建一個(gè)新的worker thread來處理C D這兩個(gè)work,從而解決了并發(fā)的問題。由于解決了并發(fā)問題,實(shí)際上也解決了由于競(jìng)爭(zhēng)一個(gè)execution context而引入的各種問題(例如dead lock)。

四、接口API

1、初始化work的接口保持不變,可以靜態(tài)或者動(dòng)態(tài)創(chuàng)建work。

2、調(diào)度work執(zhí)行也保持和舊的workqueue一致。

3、創(chuàng)建workqueue。和舊的create_workqueue接口不同,CMWQ采用了alloc_workqueue這樣的接口符號(hào),相關(guān)的接口定義如下:

在描述這些workqueue的接口之前,我們需要準(zhǔn)備一些workqueue flag的知識(shí)。

標(biāo)有WQ_UNBOUND這個(gè)flag的workqueue說明其work的處理不需要綁定在特定的CPU上執(zhí)行,workqueue需要關(guān)聯(lián)一個(gè)系統(tǒng)中的unbound worker thread pool。如果系統(tǒng)中能找到匹配的線程池(根據(jù)workqueue的屬性(attribute)),那么就選擇一個(gè),如果找不到適合的線程池,workqueue就會(huì)創(chuàng)建一個(gè)worker thread pool來處理work。

WQ_FREEZABLE是一個(gè)和電源管理相關(guān)的內(nèi)容。在系統(tǒng)Hibernation或者suspend的時(shí)候,有一個(gè)步驟就是凍結(jié)用戶空間的進(jìn)程以及部分(標(biāo)注freezable的)內(nèi)核線程(包括workqueue的worker thread)。標(biāo)記WQ_FREEZABLE的workqueue需要參與到進(jìn)程凍結(jié)的過程中,worker thread被凍結(jié)的時(shí)候,會(huì)處理完當(dāng)前所有的work,一旦凍結(jié)完成,那么就不會(huì)啟動(dòng)新的work的執(zhí)行,直到進(jìn)程被解凍。

和WQ_MEM_RECLAIM這個(gè)flag相關(guān)的概念是rescuer thread。前面我們描述解決并發(fā)問題的時(shí)候說到:對(duì)于A B C D四個(gè)work,當(dāng)正在處理的B work被阻塞后,worker pool會(huì)創(chuàng)建一個(gè)新的worker thread來處理其他的work,但是,在memory資源比較緊張的時(shí)候,創(chuàng)建worker thread未必能夠成功,這時(shí)候,如果B work是依賴C或者D work的執(zhí)行結(jié)果的時(shí)候,系統(tǒng)進(jìn)入dead lock。這種狀態(tài)是由于不能創(chuàng)建新的worker thread導(dǎo)致的,如何解決呢?對(duì)于每一個(gè)標(biāo)記WQ_MEM_RECLAIM flag的work queue,系統(tǒng)都會(huì)創(chuàng)建一個(gè)rescuer thread,當(dāng)發(fā)生這種情況的時(shí)候,C或者D work會(huì)被rescuer thread接手處理,從而解除了dead lock。

WQ_HIGHPRI說明掛入該workqueue的work是屬于高優(yōu)先級(jí)的work,需要高優(yōu)先級(jí)(比較低的nice value)的worker thread來處理。

WQ_CPU_INTENSIVE這個(gè)flag說明掛入該workqueue的work是屬于特別消耗cpu的那一類。為何要提供這樣的flag呢?我們還是用老例子來說明。對(duì)于A B C D四個(gè)work,B是cpu intersive的,當(dāng)thread正在處理B work的時(shí)候,該worker thread一直執(zhí)行B work,因?yàn)樗莄pu intensive的,特別吃cpu,這時(shí)候,thread pool是不會(huì)創(chuàng)建新的worker的,因?yàn)楫?dāng)前還有一個(gè)worker是running狀態(tài),正在處理B work。這時(shí)候C Dwork實(shí)際上是得不到執(zhí)行,影響了并發(fā)。

了解了上面的內(nèi)容,那么基本上alloc_workqueue中flag參數(shù)就明白了,下面我們轉(zhuǎn)向max_active這個(gè)參數(shù)。系統(tǒng)不能允許創(chuàng)建太多的thread來處理掛入某個(gè)workqueue的work,最多能創(chuàng)建的線程數(shù)目是定義在max_active參數(shù)中。

除了alloc_workqueue接口API之外,還可以通過alloc_ordered_workqueue這個(gè)接口API來創(chuàng)建一個(gè)嚴(yán)格串行執(zhí)行work的一個(gè)workqueue,并且該workqueue是unbound類型的。create_*的接口都是為了兼容過去接口而設(shè)立的,大家可以自行理解,這里就不多說了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8257

    瀏覽量

    149951
  • 驅(qū)動(dòng)
    +關(guān)注

    關(guān)注

    12

    文章

    1790

    瀏覽量

    84907

原文標(biāo)題:郭?。?currency Managed Workqueue(CMWQ)概述

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    為何需要進(jìn)行仿真?

    為何需要進(jìn)行仿真? Simulation and Prototyping in the Design ProcessIn order to ensure a successful circuit
    發(fā)表于 07-01 10:51

    請(qǐng)問這個(gè)函數(shù)為何需要釋放內(nèi)存?

    (10,150,100,16,16,"TMR1 STOP! ");}} }為何需要 釋放內(nèi)存呀?去掉后,程序也運(yùn)行正常!myfree(SRAMIN,pbuf);//釋放內(nèi)存
    發(fā)表于 07-11 04:35

    為什么需要這個(gè)跳線開關(guān)?

    看過“FLEX PCI Development Board”的參考設(shè)計(jì)原理圖, 它利用了條線開關(guān)選擇配置方式. 既然兩種配置方式管腳并沒有公用, 為何需要這個(gè)跳線開關(guān)?
    發(fā)表于 09-04 05:55

    柵極驅(qū)動(dòng)器是什么,為何需要柵極驅(qū)動(dòng)器?

    為何需要柵極驅(qū)動(dòng)器柵極驅(qū)動(dòng)器的關(guān)鍵參數(shù)
    發(fā)表于 12-25 06:15

    物聯(lián)網(wǎng)為何需要開源操作系統(tǒng)?物聯(lián)網(wǎng)開源操作系統(tǒng)有哪幾種?

    操作系統(tǒng)是什么?操作系統(tǒng)通常具有哪些功能?什么是開源操作系統(tǒng)?開源操作系統(tǒng)的優(yōu)勢(shì)有哪些?物聯(lián)網(wǎng)為何需要開源操作系統(tǒng)?物聯(lián)網(wǎng)開源操作系統(tǒng)有哪幾種?
    發(fā)表于 06-16 06:37

    什么是步進(jìn)電機(jī)?步進(jìn)電機(jī)為何需要驅(qū)動(dòng)電路?

    什么是步進(jìn)電機(jī)?步進(jìn)電機(jī)為何需要驅(qū)動(dòng)電路?步進(jìn)電機(jī)的有哪幾個(gè)概念?分別是什么?
    發(fā)表于 06-30 07:05

    為何需要PIDSTM32CubeMX創(chuàng)建STM32源代碼

    PID以及為何需要PIDSTM32CubeMX創(chuàng)建STM32源代碼1、何為PID以及為何需要PID??以下是PID控制的整體框圖,過程描述為:設(shè)定一個(gè)輸出目標(biāo),反饋系統(tǒng)傳回輸出值,如與目標(biāo)不一致,則存在一個(gè)誤差,PID根據(jù)此誤差調(diào)整輸入值,直至輸出達(dá)到設(shè)定值。??疑問:那
    發(fā)表于 08-10 07:49

    單片機(jī)的啟動(dòng)代碼干了些什么工作,為何需要它?

    。。。扯遠(yuǎn)了!其實(shí)電腦本身就是從單片機(jī)而來,那么單片機(jī)也是有啟動(dòng)代碼的,只是我們絕大部分情況不去關(guān)心它。啟動(dòng)代碼究竟都干了些什么工作,為何需要它?想想你在c語言中用到了什么東西,而這些東西卻是拿來...
    發(fā)表于 11-22 07:40

    為何電機(jī)起動(dòng)時(shí)閘刀開關(guān)的熔體會(huì)熔斷?如何解決?

    為何電機(jī)起動(dòng)時(shí)閘刀開關(guān)的熔體熔斷?如何解決?本文小編就給大家來分析下原因及解決方法。
    的頭像 發(fā)表于 12-14 22:46 ?788次閱讀

    工業(yè)自動(dòng)化為何需要機(jī)器視覺?工業(yè)自動(dòng)化是否需工控計(jì)算機(jī)?

    工業(yè)自動(dòng)化技術(shù)日益成熟,大家對(duì)于工業(yè)自動(dòng)化均有所耳聞。但是,大家對(duì)工業(yè)自動(dòng)化真的了解嗎?工業(yè)自動(dòng)化中為何使用機(jī)器視覺?工業(yè)自動(dòng)化中又為何需使用工控計(jì)算機(jī)?對(duì)于這些問題,大家心中是否具有明確答案?如果你對(duì)這些問題具有疑惑,不妨在本文中尋求答案哦
    的頭像 發(fā)表于 12-24 20:23 ?701次閱讀

    為何電機(jī)起動(dòng)時(shí)閘刀開關(guān)的熔體熔斷?如何解決?

    為何電機(jī)起動(dòng)時(shí)閘刀開關(guān)的熔體熔斷?如何解決?本文小編就給大家來分析下原因及解決方法。
    發(fā)表于 02-05 07:08 ?5次下載
    <b class='flag-5'>為何</b>電機(jī)起動(dòng)時(shí)閘刀開關(guān)的熔體熔斷?如<b class='flag-5'>何解</b>決?

    什么是運(yùn)輸節(jié)電模式 為何需要

    。 圖 1:拉動(dòng)電池供電產(chǎn)品上的拉片 什么是運(yùn)輸節(jié)電模式,為何需要它? 運(yùn)輸節(jié)電模式是產(chǎn)品消耗最低電池電流的狀態(tài)。消費(fèi)者希望在購買電池供電產(chǎn)品后能夠立即使用它們。這意味著電池在運(yùn)輸期間
    的頭像 發(fā)表于 01-15 10:20 ?1453次閱讀

    何謂沖擊電流?為何需要沖擊電流防止電路?

    何謂沖擊電流?為何需要沖擊電流防止電路? 沖擊電流是指在電路中瞬時(shí)地流過較高的電流。它通常在開關(guān)電源、電機(jī)、變壓器等設(shè)備啟動(dòng)或停止時(shí)發(fā)生。這種電流瞬間產(chǎn)生,具有高峰值和短時(shí)間的特征。如果沒有采取措施
    的頭像 發(fā)表于 10-27 14:24 ?3125次閱讀

    何為PID?為何需要PID?PID能達(dá)到什么作用?

    何為PID?為何需要PID?PID能達(dá)到什么作用? PID是英文Proportional-Integral-Derivative的縮寫,即比例-積分-微分控制器。它是一種常用的反饋控制手段,常用
    的頭像 發(fā)表于 12-07 13:37 ?1175次閱讀

    單片機(jī)為何需要Flash和EEPROM?它們有何作用?

    單片機(jī)為何需要Flash和EEPROM?它們有何作用? 單片機(jī)是一種集成電路,具有處理器核心、內(nèi)存和外設(shè)等功能,通常用于嵌入式系統(tǒng)中。Flash和EEPROM則是單片機(jī)中常用的存儲(chǔ)器類型,它們具有
    的頭像 發(fā)表于 01-18 11:43 ?2737次閱讀