read 系統(tǒng)調(diào)用剖析
級別:初級
趙健博(),碩士,中國科學院計算技術(shù)研究所
2008 年 3 月 13 日
大部分程序員可能會有這樣的疑問:當在程序中調(diào)用庫函數(shù) read 時,這個請求是經(jīng)過哪些處理最終到達磁盤的呢,數(shù)據(jù)又是怎么被拷貝到用戶緩存區(qū)的呢?本文介紹了從 read 系統(tǒng)調(diào)用發(fā)出到結(jié)束處理的全過程。該過程包括兩個部分:用戶空間的處理、核心空間的處理。用戶空間處理部分是系統(tǒng)調(diào)用從用戶態(tài)切到核心態(tài)的過程。核心空間處理部分則是 read 系統(tǒng)調(diào)用在 linux 內(nèi)核中處理的整個過程。Read 系統(tǒng)調(diào)用在用戶空間中的處理過程
Linux 系統(tǒng)調(diào)用(SCI,system call interface)的實現(xiàn)機制實際上是一個多路匯聚以及分解的過程,該匯聚點就是 0x80 中斷這個入口點(X86 系統(tǒng)結(jié)構(gòu))。也就是說,所有系統(tǒng)調(diào)用都從用戶空間中匯聚到 0x80 中斷點,同時保存具體的系統(tǒng)調(diào)用號。當 0x80 中斷處理程序運行時,將根據(jù)系統(tǒng)調(diào)用號對不同的系統(tǒng)調(diào)用分別處理(調(diào)用不同的內(nèi)核函數(shù)處理)。系統(tǒng)調(diào)用的更多內(nèi)容,請參見參考資料。
Read 系統(tǒng)調(diào)用也不例外,當調(diào)用發(fā)生時,庫函數(shù)在保存 read 系統(tǒng)調(diào)用號以及參數(shù)后,陷入 0x80 中斷。這時庫函數(shù)工作結(jié)束。Read 系統(tǒng)調(diào)用在用戶空間中的處理也就完成了。
Read 系統(tǒng)調(diào)用在核心空間中的處理過程
0x80 中斷處理程序接管執(zhí)行后,先檢察其系統(tǒng)調(diào)用號,然后根據(jù)系統(tǒng)調(diào)用號查找系統(tǒng)調(diào)用表,并從系統(tǒng)調(diào)用表中得到處理 read 系統(tǒng)調(diào)用的內(nèi)核函數(shù)sys_read,最后傳遞參數(shù)并運行 sys_read 函數(shù)。至此,內(nèi)核真正開始處理read 系統(tǒng)調(diào)用(sys_read 是 read 系統(tǒng)調(diào)用的內(nèi)核入口)。
在講解 read 系統(tǒng)調(diào)用在核心空間中的處理部分中,首先介紹了內(nèi)核處理磁盤請求的層次模型,然后再按該層次模型從上到下的順序依次介紹磁盤讀請求在各層的處理過程。
Read 系統(tǒng)調(diào)用在核心空間中處理的層次模型
圖 1 顯示了 read 系統(tǒng)調(diào)用在核心空間中所要經(jīng)歷的層次模型。從圖中看出:對于磁盤的一次讀請求,首先經(jīng)過虛擬文件系統(tǒng)層(vfs layer),其次是具體的文件系統(tǒng)層(例如 ext2),接下來是 cache 層(page cache 層)、通用塊層(generic block layer)、IO 調(diào)度層(I/O scheduler layer)、塊設(shè)備驅(qū)動層(block device driver layer),最后是物理塊設(shè)備層(block device layer)
圖 1 read 系統(tǒng)調(diào)用在核心空間中的處理層次
虛擬文件系統(tǒng)層的作用:屏蔽下層具體文件系統(tǒng)操作的差異,為上層的操作提供一個統(tǒng)一的接口。正是因為有了這個層次,所以可以把設(shè)備抽象成文件,使得操作設(shè)備就像操作文件一樣簡單。在具體的文件系統(tǒng)層中,不同的文件系統(tǒng)(例如 ext2 和 NTFS)具體的操作過程也是不同的。每種文件系統(tǒng)定義了自己的操作集合。關(guān)于文件系統(tǒng)的更多內(nèi)容,請參見參考資料。引入 cache 層的目的是為了提高 linux 操作系統(tǒng)對磁盤訪問的性能。Cache 層在內(nèi)存中緩存了磁盤上的部分數(shù)據(jù)。當數(shù)據(jù)的請求到達時,如果在 cache 中存在該數(shù)據(jù)且是最新的,則直接將數(shù)據(jù)傳遞給用戶程序,免除了對底層磁盤的操作,提高了性能。通用塊層的主要工作是:接收上層發(fā)出的磁盤請求,并最終發(fā)出 IO 請求。該層隱藏了底層硬件塊設(shè)備的特性,為塊設(shè)備提供了一個通用的抽象視圖。IO調(diào)度層的功能:接收通用塊層發(fā)出的 IO 請求,緩存請求并試圖合并相鄰的請求(如果這兩個請求的數(shù)據(jù)在磁盤上是相鄰的)。并根據(jù)設(shè)置好的調(diào)度算法,回調(diào)驅(qū)動層提供的請求處理函數(shù),以處理具體的 IO 請求。驅(qū)動層中的驅(qū)動程序?qū)?yīng)具體的物理塊設(shè)備。它從上層中取出 IO 請求,并根據(jù)該 IO 請求中指定的信息,通過向具體塊設(shè)備的設(shè)備控制器發(fā)送命令的方式,來操縱設(shè)備傳輸數(shù)據(jù)。設(shè)備層中都是具體的物理設(shè)備。定義了操作具體設(shè)備的規(guī)范。相關(guān)的內(nèi)核數(shù)據(jù)結(jié)構(gòu):
Dentry:聯(lián)系了文件名和文件的 i 節(jié)點 inode:文件 i 節(jié)點,保存文件標識、權(quán)限和內(nèi)容等信息 file:保存文件的相關(guān)信息和各種操作文件的函數(shù)指針集合:操作文件的函數(shù)接口集合 address_space:描述文件的 page cache 結(jié)構(gòu)以及相關(guān)信息,并包含有操作 page cache 的函數(shù)指針集合address_space_operations:操作 page cache 的函數(shù)接口集合 bio:IO 請求的描述數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系:
圖 2 示意性地展示了上述各個數(shù)據(jù)結(jié)構(gòu)(除了 bio)之間的關(guān)系。可以看出:由 dentry 對象可以找到 inode 對象,從 inode 對象中可以取出
address_space 對象,再由 address_space 對象找到address_space_operations 對象。
File 對象可以根據(jù)當前進程描述符中提供的信息取得,進而可以找到dentry 對象、address_space 對象和對象。
圖 2 數(shù)據(jù)結(jié)構(gòu)關(guān)系圖:
前提條件:
對于具體的一次 read 調(diào)用,內(nèi)核中可能遇到的處理情況很多。這里舉例其中的一種情況:
要讀取的文件已經(jīng)存在文件經(jīng)過 page cache 要讀的是普通文件磁盤上文件系統(tǒng)為 ext2 文件系統(tǒng),有關(guān) ext2 文件系統(tǒng)的相關(guān)內(nèi)容,參見參考資料準備:
注:所有清單中代碼均來自 linux 2.6.11 內(nèi)核原代碼
讀數(shù)據(jù)之前,必須先打開文件。處理 open 系統(tǒng)調(diào)用的內(nèi)核函數(shù)為sys_open。所以我們先來看一下該函數(shù)都作了哪些事。清單 1 顯示了 sys_open的代碼(省略了部分內(nèi)容,以后的程序清單同樣方式處理)
清單 1 sys_open 函數(shù)代碼
asmlinkage long sys_open(const char __user* flags,int mode){…fd=get_unused_fd();if(fd=0){struct (tmp,flags,mode);fd_install(fd,f);}…return fd;…}
代碼解釋:
get_unuesed_fd():取回一個未被使用的文件描述符(每次都會選取最小的未被使用的文件描述符)。filp_open():調(diào)用 open_namei()函數(shù)取出和該文件相關(guān)的 dentry 和 inode(因為前提指明了文件已經(jīng)存在,所以 dentry 和 inode能夠查找到,不用創(chuàng)建),然后調(diào)用 dentry_open()函數(shù)創(chuàng)建新的 file 對象,并用 dentry 和 inode 中的信息初始化 file 對象(文件當前的讀寫位置在 file對象中保存)。注意到 dentry_open()中有一條語句:f-f_op=fops_get(inode-i_fop);
這個賦值語句把和具體文件系統(tǒng)相關(guān)的,操作文件的函數(shù)指針集合賦給了file 對象的 f _op 變量(這個指針集合是保存在 inode 對象中的),在接下來的sys_read 函數(shù)中將會調(diào)用中的成員 read。
fd_install():以文件描述符為索引,關(guān)聯(lián)當前進程描述符和上述的 file對象,為之后的 read 和 write 等操作作準備。函數(shù)最后返回該文件描述符。圖3 顯示了 sys_open 函數(shù)返回后,file 對象和當前進程描述符之間的關(guān)聯(lián)關(guān)系,以及 file 對象中操作文件的函數(shù)指針集合的來源(inode 對象中的成員i_fop)。
圖 3 file 對象和當前進程描述符之間的關(guān)系
到此為止,所有的準備工作已經(jīng)全部結(jié)束了,下面開始介紹 read 系統(tǒng)調(diào)用在圖 1 所示的各個層次中的處理過程。
虛擬文件系統(tǒng)層的處理:
內(nèi)核函數(shù) sys_read()是 read 系統(tǒng)調(diào)用在該層的入口點,清單 2 顯示了該函數(shù)的代碼。
清單 2 sys_read 函數(shù)的代碼
asmlinkage ssize_t sys_read(unsigned int fd,char __user*buf,size_t count){struct ;ssize_t ret=-EBADF;int fput_needed;(fd,&fput_needed);if(file){loff_t pos=(file);ret=vfs_read();();fput_light();}return ret;}
代碼解析:
fget_light():根據(jù) fd 指定的索引,從當前進程描述符中取出相應(yīng)的file 對象(見圖 3)。如果沒找到指定的 file 對象,則返回錯誤如果找到了指定的 file 對象:調(diào)用()函數(shù)取出此次讀寫文件的當前位置。調(diào)用 vfs_read()執(zhí)行文件讀取操作,而這個函數(shù)最終調(diào)用()指向的函數(shù),代碼如下:if()ret=();
調(diào)用()更新文件的當前讀寫位置。調(diào)用 fput_light()更新文件的引用計數(shù)。最后返回讀取數(shù)據(jù)的字節(jié)數(shù)。到此,虛擬文件系統(tǒng)層所做的處理就完成了,控制權(quán)交給了 ext2 文件系統(tǒng)層。
在解析 ext2 文件系統(tǒng)層的操作之前,先讓我們看一下 file 對象中 read 指針來源。
File 對象中 read 函數(shù)指針的來源:
從前面對 sys_open 內(nèi)核函數(shù)的分析來看,來自于 inode-i_fop。那么inode-i_fop 來自于哪里呢?在初始化 inode 對象時賦予的。見清單 3。
清單 3 ext2_read_inode()函數(shù)部分代碼
void ext2_read_inode(struct inode*inode){…if(S_ISREG(inode-i_mode)){inode-i_op=&ext2_;inode-i_fop=&ext2_;if(test_opt(inode-i_sb,NOBH))inode-i_mapping-a_ops=&ext2_nobh_aops;else inode-i_mapping-a_ops=&ext2_aops;}…}
從代碼中可以看出,如果該 inode 所關(guān)聯(lián)的文件是普通文件,則將變量ext2_的地址賦予 inode 對象的 i_fop 成員。所以可以知道:inode-i_fop.read函數(shù)指針所指向的函數(shù)為 ext2_變量的成員 read 所指向的函數(shù)。下面來看一下ext2_變量的初始化過程,如清單 4。
清單 4 ext2_的初始化
struct
ext2_{.llseek=generic_,};
該成員 read 指向函數(shù) generic_。所以,inode-i_fop.read 指向 generic_函數(shù),進而指向 generic_函數(shù)。最終得出結(jié)論:generic_函數(shù)才是 ext2 層的真實入口。
Ext2 文件系統(tǒng)層的處理
圖 4 read 系統(tǒng)調(diào)用在 ext2 層中處理時函數(shù)調(diào)用關(guān)系
由圖 4 可知,該層入口函數(shù) generic_調(diào)用函數(shù)__generic_,后者判斷本次讀請求的訪問方式,如果是直接 io(filp-f_flags 被設(shè)置了 O_DIRECT 標志,即不經(jīng)過 cache)的方式,則調(diào)用 generic_函數(shù);如果是 page cache 的方式,則調(diào)用 do_generic_函數(shù)。函數(shù) do_generic_僅僅是一個包裝函數(shù),它又調(diào)用do_generic_mapping_read 函數(shù)。
在講解 do_generic_mapping_read 函數(shù)都作了哪些工作之前,我們再來看一下文件在內(nèi)存中的緩存區(qū)域是被怎么組織起來的。
文件的 page cache 結(jié)構(gòu)
圖 5 顯示了一個文件的 page cache 結(jié)構(gòu)。文件被分割為一個個以 page 大小為單元的數(shù)據(jù)塊,這些數(shù)據(jù)塊(頁)被組織成一個多叉樹(稱為 radix 樹)。樹中所有葉子節(jié)點為一個個頁幀結(jié)構(gòu)(struct page),表示了用于緩存該文件的每一
個頁。在葉子層最左端的第一個頁保存著該文件的前 4096 個字節(jié)(如果頁的大小為 4096 字節(jié)),接下來的頁保存著文件第二個 4096 個字節(jié),依次類推。樹中的所有中間節(jié)點為組織節(jié)點,指示某一地址上的數(shù)據(jù)所在的頁。此樹的層次可以從 0 層到 6 層,所支持的文件大小從 0 字節(jié)到 16 T 個字節(jié)。樹的根節(jié)點指針可以從和文件相關(guān)的 address_space 對象(該對象保存在和文件關(guān)聯(lián)的 inode 對象中)中取得(更多關(guān)于 page cache 的結(jié)構(gòu)內(nèi)容請參見參考資料)。
圖 5 文件的 page cache 結(jié)構(gòu)
現(xiàn)在,我們來看看函數(shù) do_generic_mapping_read 都作了哪些工作,do_generic_mapping_read 函數(shù)代碼較長,本文簡要介紹下它的主要流程:
根據(jù)文件當前的讀寫位置,在 page cache 中找到緩存請求數(shù)據(jù)的 page 如果該頁已經(jīng)最新,將請求的數(shù)據(jù)拷貝到用戶空間否則,Lock 該頁調(diào)用 readpage函數(shù)向磁盤發(fā)出添頁請求(當下層完成該 IO 操作時會解鎖該頁),代碼:error=mapping-a_ops-readpage(filp,page);
再一次 lock 該頁,操作成功時,說明數(shù)據(jù)已經(jīng)在 page cache 中了,因為只有 IO 操作完成后才可能解鎖該頁。此處是一個同步點,用于同步數(shù)據(jù)從磁盤到內(nèi)存的過程。解鎖該頁到此為止數(shù)據(jù)已經(jīng)在 page cache 中了,再將其拷貝到用戶空間中(之后 read 調(diào)用可以在用戶空間返回了)到此,我們知道:當頁上的數(shù)據(jù)不是最新的時候,該函數(shù)調(diào)用 mapping-a_ops-readpage 所指向的函數(shù)(變量 mapping 為 inode 對象中的 address_space 對象),那么這個函數(shù)到底是什么呢?
Readpage 函數(shù)的由來
address_space 對象是嵌入在 inode 對象之中的,那么不難想象:address_space 對象成員 a_ops 的初始化工作將會在初始化 inode 對象時進行。如清單 3 中后半部所顯示。
if(test_opt(inode-i_sb,NOBH))inode-i_mapping-a_ops=&ext2_nobh_aops;else inode-i_mapping-a_ops=&ext2_aops;
可以知道 address_space 對象的成員 a_ops 指向變量 ext2_aops 或者變量ext2_nobh_aops。這兩個變量的初始化如清單 5 所示。
清單 5 變量 ext2_aops 和變量 ext2_nobh_aops 的初始化
struct address_space_operations ext2_aops={.readpage=ext2_readpage,.readpages=ext2_readpages,.writepage=ext2_writepage,.sync_page=block_sync_page,.prepare_write=ext2_prepare_write,.commit_write=generic_commit_write,.bmap=ext2_bmap,.direct_IO=ext2_direct_IO,.writepages=ext2_writepages,};struct address_space_operations ext2_nobh_aops={.readpage=ext2_readpage,.readpages=ext2_readpages,.writepage=ext2_writepage,.sync_page=block_sync_page,.prepare_write=ext2_nobh_prepare_write,.commit_write=nobh_commit_write,.bmap=ext2_bmap,.direct_IO=ext2_direct_IO,.writepages=ext2_writepages,};
從上述代碼中可以看出,不論是哪個變量,其中的 readpage 成員都指向函數(shù) ext2_readpage。所以可以斷定:函數(shù) do_generic_mapping_read 最終調(diào)用ext2_readpage 函數(shù)處理讀數(shù)據(jù)請求。
到此為止,ext2 文件系統(tǒng)層的工作結(jié)束。
Page cache 層的處理
從上文得知:ext2_readpage 函數(shù)是該層的入口點。該函數(shù)調(diào)用mpage_readpage 函數(shù),清單 6 顯示了 mpage_readpage 函數(shù)的代碼。
清單 6 mpage_readpage 函數(shù)的代碼
int mpage_readpage(struct page*page,get_block_t get_block){struct bio*bio=NULL;sector_t last_block_in_bio=0;bio=do_mpage_readpage(bio,page,1,&last_block_in_bio,get_block);if(bio)mpage_bio_submit(READ,bio);return 0;}
該函數(shù)首先調(diào)用函數(shù) do_mpage_readpage 函數(shù)創(chuàng)建了一個 bio 請求,該請求指明了要讀取的數(shù)據(jù)塊所在磁盤的位置、數(shù)據(jù)塊的數(shù)量以及拷貝該數(shù)據(jù)的目標位置--緩存區(qū)中 page 的信息。然后調(diào)用 mpage_bio_submit 函數(shù)處理請求。mpage_bio_submit 函數(shù)則調(diào)用 submit_bio 函數(shù)處理該請求,后者最終將請求傳遞給函數(shù) generic_make_request,并由 generic_make_request 函數(shù)將請求提交給通用塊層處理。
到此為止,page cache 層的處理結(jié)束。
通用塊層的處理
generic_make_request 函數(shù)是該層的入口點,該層只有這一個函數(shù)處理請求。清單 7 顯示了函數(shù)的部分代碼
清單 7 generic_make_request 函數(shù)部分代碼
void generic_make_request(struct bio*bio){…do{char b[BDEVNAME_SIZE];q=bdev_get_queue(bio-bi_bdev);…block_wait_queue_running(q);/**If this device has partitions,remap block n*of partition pto block n+start(p)of the disk.*/blk_partition_remap(bio);ret=q-make_request_fn(q,bio);}while(ret);}
主要操作:
根據(jù) bio 中保存的塊設(shè)備號取得請求隊列 q 檢測當前 IO 調(diào)度器是否可用,如果可用,則繼續(xù);否則等待調(diào)度器可用調(diào)用 q-make_request_fn 所指向的函數(shù)將該請求(bio)加入到請求隊列中到此為止,通用塊層的操作結(jié)束。
IO 調(diào)度層的處理
對 make_request_fn 函數(shù)的調(diào)用可以認為是 IO 調(diào)度層的入口,該函數(shù)用于向請求隊列中添加請求。該函數(shù)是在創(chuàng)建請求隊列時指定的,代碼如下(blk_init_queue 函數(shù)中):
q-request_fn=rfn;blk_queue_make_request(q,__make_request);
函數(shù) blk_queue_make_request 將函數(shù)__make_request 的地址賦予了請求隊列 q 的 make_request_fn 成員,那么,__make_request 函數(shù)才是 IO 調(diào)度層的真實入口。
__make_request 函數(shù)的主要工作為:
檢測請求隊列是否為空,若是,延緩驅(qū)動程序處理當前請求(其目的是想積累更多的請求,這樣就有機會對相鄰的請求進行合并,從而提高處理的性能),并跳到 3,否則跳到 2 試圖將當前請求同請求隊列中現(xiàn)有的請求合并,如果合并成功,則函數(shù)返回,否則跳到 3 該請求是一個新請求,創(chuàng)建新的請求描述符,并初始化相應(yīng)的域,并將該請求描述符加入到請求隊列中,函數(shù)返回將請求放入到請求隊列中后,何時被處理就由 IO 調(diào)度器的調(diào)度算法決定了(有關(guān) IO調(diào)度器的算法內(nèi)容請參見參考資料)。一旦該請求能夠被處理,便調(diào)用請求隊列
中成員 request_fn 所指向的函數(shù)處理。這個成員的初始化也是在創(chuàng)建請求隊列時設(shè)置的:
q-request_fn=rfn;blk_queue_make_request(q,__make_request);
第一行是將請求處理函數(shù) rfn 指針賦給了請求隊列的 request_fn 成員。而rfn 則是在創(chuàng)建請求隊列時通過參數(shù)傳入的。
對請求處理函數(shù) request_fn 的調(diào)用意味著 IO 調(diào)度層的處理結(jié)束了。
塊設(shè)備驅(qū)動層的處理
request_fn 函數(shù)是塊設(shè)備驅(qū)動層的入口。它是在驅(qū)動程序創(chuàng)建請求隊列時由驅(qū)動程序傳遞給 IO 調(diào)度層的。
IO 調(diào)度層通過回調(diào) request_fn 函數(shù)的方式,把請求交給了驅(qū)動程序。而驅(qū)動程序從該函數(shù)的參數(shù)中獲得上層發(fā)出的 IO 請求,并根據(jù)請求中指定的信息操作設(shè)備控制器(這一請求的發(fā)出需要依據(jù)物理設(shè)備指定的規(guī)范進行)。
到此為止,塊設(shè)備驅(qū)動層的操作結(jié)束。
塊設(shè)備層的處理
接受來自驅(qū)動層的請求,完成實際的數(shù)據(jù)拷貝工作等等。同時規(guī)定了一系列規(guī)范,驅(qū)動程序必須按照這個規(guī)范操作硬件。
后續(xù)工作
當設(shè)備完成了 IO 請求之后,通過中斷的方式通知 cpu,而中斷處理程序又會調(diào)用 request_fn 函數(shù)進行處理。
當驅(qū)動再次處理該請求時,會根據(jù)本次數(shù)據(jù)傳輸?shù)慕Y(jié)果通知上層函數(shù)本次IO 操作是否成功,如果成功,上層函數(shù)解鎖 IO 操作所涉及的頁面(在do_generic_mapping_read 函數(shù)中加的鎖)。
該頁被解鎖后,do_generic_mapping_read()函數(shù)就可以再次成功獲得該鎖(數(shù)據(jù)的同步點),并繼續(xù)執(zhí)行程序了。之后,函數(shù) sys_read 可以返回了。最終read 系統(tǒng)調(diào)用也可以返回了。
至此,read 系統(tǒng)調(diào)用從發(fā)出到結(jié)束的整個處理過程就全部結(jié)束了。
本文介紹了 linux 系統(tǒng)調(diào)用 read 的處理全過程。該過程分為兩個部分:用戶空間的處理和核心空間的處理。在用戶空間中通過 0x80 中斷的方式將控制權(quán)交給內(nèi)核處理,內(nèi)核接管后,經(jīng)過 6 個層次的處理最后將請求交給磁盤,由磁盤完成最終的數(shù)據(jù)拷貝操作。在這個過程中,調(diào)用了一系列的內(nèi)核函數(shù)。如圖6
圖 6 read 系統(tǒng)調(diào)用在內(nèi)核中所經(jīng)歷的函數(shù)調(diào)用層次
參考資料
查看文章"使用 Linux 系統(tǒng)調(diào)用的內(nèi)核命令",了解系統(tǒng)調(diào)用的基本原理以及如何實現(xiàn)自己的系統(tǒng)調(diào)用的方法。查看文章"Linux 文件系統(tǒng)剖析",了解linux 文件系統(tǒng)的相關(guān)內(nèi)容。參看文章"Ext2 文件系統(tǒng)的硬盤布局"和書籍"understanding the linux kernel(3rd edition)"第 18 章的內(nèi)容,了解 ext2文件系統(tǒng)的相關(guān)內(nèi)容。查看書籍"understanding the linux kernel(3rd edition)"第 14、15 章內(nèi)容,了解 IO 調(diào)度算法、page cache 的技術(shù)等內(nèi)容。
關(guān)于作者
趙健博,2006 級碩士計算技術(shù)研究所國家智能計算機研究開發(fā)中心體系結(jié)構(gòu)組,目前從事體系結(jié)構(gòu)和操作系統(tǒng)相關(guān)的工作。
特別聲明:
1 :資料來源于互聯(lián)網(wǎng),版權(quán)歸屬原作者 2 :資料內(nèi)容屬于網(wǎng)絡(luò)意見,與本賬號立場無關(guān) 3 :如有侵權(quán),請告知,立即刪除。
推薦訪問: 調(diào)用 剖析 系統(tǒng)在偉大祖國73華誕之際,我參加了單位組織的“光影鑄魂”主題黨日活動,集中觀看了抗美援朝題材影片《長津湖》,再一次重溫這段悲壯歷史,再一次深刻感悟偉大抗美援朝精神。1950年10月,新中國剛剛成立一年,
根據(jù)省局黨組《關(guān)于舉辦習近平談治國理政(第四卷)讀書班的通知》要求,我中心通過專題學習、專題研討以及交流分享等形式,系統(tǒng)的對《習近平談治國理政》(第四卷)進行了深入的學習與交流,下面我就來談一談我個人
《習近平談治國理政》(第四卷)是在百年變局和世紀疫情相互疊加的大背景下,對以習近平同志為核心的黨中央治國理政重大戰(zhàn)略部署、重大理論創(chuàng)造、重大思想引領(lǐng)的系統(tǒng)呈現(xiàn)。它生動記錄了新一代黨中央領(lǐng)導(dǎo)集體統(tǒng)籌兩個
《真抓實干做好新發(fā)展階段“三農(nóng)工作”》是《習近平談治國理政》第四卷中的文章,這是習近平總書記在2020年12月28日中央農(nóng)村工作會議上的集體學習時的講話。文章指出,我常講,領(lǐng)導(dǎo)干部要胸懷黨和國家工作大
在《習近平談治國理政》第四卷中,習近平總書記強調(diào),江山就是人民,人民就是江山,打江山、守江山,守的是人民的心。從嘉興南湖中駛出的小小紅船,到世界上最大的執(zhí)政黨,在中國共產(chǎn)黨的字典里,“人民”一詞從來都
黨的十八大以來,習近平總書記以馬克思主義戰(zhàn)略家的博大胸襟和深謀遠慮,在治國理政和推動全球治理中牢固樹立戰(zhàn)略意識,在不同場合多次圍繞戰(zhàn)略策略的重要性,戰(zhàn)略和策略的關(guān)系,提高戰(zhàn)略思維、堅定戰(zhàn)略自信、強化戰(zhàn)
《習近平談治國理政》第四卷集中展示了以習近平同志為核心的黨中央在百年變局和世紀疫情相互疊加背景下,如何更好地堅持和發(fā)展中國特色社會主義而進行的生動實踐與理論探索;對于新時代堅持和發(fā)展什么樣的中國特色社
在黨組織的關(guān)懷下,我有幸參加了區(qū)委組織部組織的入黨積極分子培訓班。為期一周的學習,學習形式多樣,課程內(nèi)容豐富,各位專家的講解細致精彩,對于我加深對黨的創(chuàng)新理論的認識、對黨的歷史的深入了解、對中共黨員的
《習近平談治國理政》第四卷《共建網(wǎng)上美好精神家園》一文中指出:網(wǎng)絡(luò)玩命是新形勢下社會文明的重要內(nèi)容,是建設(shè)網(wǎng)絡(luò)強國的重要領(lǐng)域。截至2021年12月,我國網(wǎng)民規(guī)模達10 32億,較2020年12月增長4
剛剛召開的中國共產(chǎn)黨第十九屆中央委員會第七次全體會議上討論并通過了黨的十九屆中央委員會向中國共產(chǎn)黨第二十次全國代表大會的報告、黨的十九屆中央紀律檢查委員會向中國共產(chǎn)黨第二十次全國代表大會的工作報告和《