日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
高效穩(wěn)定!探究Linux異步讀寫機(jī)制(linux異步讀寫)

在計(jì)算機(jī)領(lǐng)域中,穩(wěn)定和高效是應(yīng)用程序所關(guān)注的主要問題。尤其在大數(shù)據(jù)時(shí)代,數(shù)據(jù)的處理速度和準(zhǔn)確性對于應(yīng)用程序來說是至關(guān)重要的。因此,Linux操作系統(tǒng)的異步讀寫機(jī)制為開發(fā)者提供了一個(gè)穩(wěn)定和高效的解決方案。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:申請域名、網(wǎng)頁空間、營銷軟件、網(wǎng)站建設(shè)、武川網(wǎng)站維護(hù)、網(wǎng)站推廣。

什么是異步讀寫?

異步讀寫是一種計(jì)算機(jī)技術(shù),允許應(yīng)用程序執(zhí)行讀寫操作的同時(shí),允許其他操作同時(shí)進(jìn)行。在傳統(tǒng)的同步讀寫中,應(yīng)用程序會(huì)一直等待I/O操作完成后才能繼續(xù)執(zhí)行。這可能會(huì)導(dǎo)致程序在I/O操作完成之前處于無限期的掛起狀態(tài),最終造成系統(tǒng)性能下降。

相比之下,異步讀寫機(jī)制使應(yīng)用程序能夠自由地繼續(xù)執(zhí)行,而無需等待I/O操作的完成。應(yīng)用程序只需要請求操作,然后I/O操作會(huì)在后臺(tái)進(jìn)行。一旦操作完成,I/O操作會(huì)通知應(yīng)用程序完成了。這種機(jī)制提高了應(yīng)用程序的吞吐量,允許系統(tǒng)上其他任務(wù)在進(jìn)行時(shí)執(zhí)行I/O操作。

如何使用Linux異步讀寫?

Linux異步讀寫通過一系列系統(tǒng)調(diào)用來實(shí)現(xiàn)。常用的有以下幾種:

1. open()

在開始異步讀寫過程之前,必須打開包含要讀寫的文件的文件描述符。使用open()系統(tǒng)調(diào)用打開文件,該調(diào)用返回一個(gè)文件描述符,以便將來進(jìn)行I/O操作。

2. o_read() 和 o_write()

異步I/O操作是通過o_read()和o_write()系統(tǒng)調(diào)用來實(shí)現(xiàn)的。這些調(diào)用可以讓應(yīng)用程序執(zhí)行讀/寫操作,然后立即返回。操作被放到內(nèi)核隊(duì)列中,以便在后臺(tái)執(zhí)行,而不會(huì)與應(yīng)用程序的其他操作干擾。

3. o_error() 和 o_return()

o_error()和o_return()系統(tǒng)調(diào)用可用于檢查異步I/O操作的狀態(tài)和結(jié)果。o_error()用于檢查異步操作的錯(cuò)誤狀態(tài)。而o_return()則返回阻塞進(jìn)程的I/O操作的結(jié)果。這個(gè)結(jié)果也可以在操作完成時(shí)異步通知。

為什么要使用Linux異步讀寫?

Linux異步讀寫有許多優(yōu)點(diǎn),其中一些包括:

1.提高了應(yīng)用程序的吞吐量

異步讀寫允許應(yīng)用程序執(zhí)行I/O操作的同時(shí),執(zhí)行其他任務(wù)。在傳統(tǒng)的同步讀寫中,應(yīng)用程序會(huì)一直等待I/O操作完成后才能繼續(xù)執(zhí)行。這可能會(huì)導(dǎo)致程序在I/O操作完成之前無限期的掛起,造成系統(tǒng)性能的下降。

2.節(jié)省CPU資源

異步I/O操作可以在后臺(tái)執(zhí)行,而不會(huì)消耗CPU資源。這節(jié)省了CPU資源,可以用來支持其他應(yīng)用程序和操作。

3.減少內(nèi)存和磁盤的I/O操作延遲

在多線程應(yīng)用程序中,當(dāng)線程需要等待I/O操作完成時(shí),它們通常會(huì)傳遞控制到其他線程,以充分利用系統(tǒng)上的其他資源。然而,這可能會(huì)導(dǎo)致磁盤I/O操作的延遲,從而影響整個(gè)應(yīng)用程序的性能。異步I/O操作可以在后臺(tái)進(jìn)行,而線程可以繼續(xù)工作。這減少了I/O操作的延遲,進(jìn)一步提高了應(yīng)用程序的性能。

Linux異步讀寫機(jī)制能夠提高應(yīng)用程序的效率,同時(shí)還消除了I/O操作的延遲等待。它是大規(guī)模數(shù)據(jù)應(yīng)用程序的理想解決方案之一,因?yàn)樵谌绱酥蟮臄?shù)據(jù)量下,同步讀寫將會(huì)成為一個(gè)瓶頸。該機(jī)制為應(yīng)用程序提供了一個(gè)穩(wěn)定和高效的解決方案,不斷推動(dòng)著技術(shù)和經(jīng)驗(yàn)的進(jìn)步和提高。

相關(guān)問題拓展閱讀:

  • linux磁盤格式化與管理知識(shí)點(diǎn)總結(jié)
  • 如何實(shí)現(xiàn)linux下多線程之間的互斥與同步

linux磁盤格式化與管理知識(shí)點(diǎn)總結(jié)

首先我們來認(rèn)識(shí)下Linux上的文件系統(tǒng)

  /:根目錄

  /bin:二進(jìn)制,可執(zhí)行命令

  /in:可執(zhí)行命令,僅用于管理,通常只有管理員才有權(quán)限使用。

  /boot:引導(dǎo),操作系統(tǒng)用于引導(dǎo)系統(tǒng)啟動(dòng)的文件,一般指內(nèi)核

  /dev:設(shè)備文件

  Linux的設(shè)備類型

  字符設(shè)備:以c開頭的文件,線性設(shè)備

  塊設(shè)備:以b開頭的文件,隨機(jī)設(shè)備

  /etc:配置文件

  /home:用戶的家目錄,/home/username,eg:jerry,/home/jerry

  /lib,/lib64:庫文件

  /media:掛載點(diǎn)目錄,通常用于掛在便攜性設(shè)備

  /mnt:掛載點(diǎn)目錄,掛在額外的文件系統(tǒng)

  /misc:備份目錄

  /net

  /opt可選目錄,通常第三方軟件偶爾安裝于此路徑下

  /proc:偽文件系統(tǒng),內(nèi)存中內(nèi)核的映射

  /selinux: 安全加強(qiáng)的linux

  /srv: service 屬于服務(wù)的中間數(shù)據(jù)存儲(chǔ)位置

  /sys:類似于proc,通常用于訪問獲取硬件設(shè)備屬性信息

  /tmp:臨時(shí)文件目錄

  /usr:存放只讀文件

  /var:經(jīng)常會(huì)發(fā)生變化的文件,比方說日志等

  文件系統(tǒng)通常有內(nèi)核提供,Windows里邊的文件系統(tǒng)有:NTFS、FAT32 Linux里邊的文件系統(tǒng)主要由ext2,ext3,ext4,xfs,reiserfs,nfs,iso9600,jfs,brtfs

  對磁盤格式化就是創(chuàng)建文件系統(tǒng),那么怎么實(shí)現(xiàn)格式化的呢?下面介紹一下實(shí)現(xiàn)磁盤格式化的命令及用法

  之一步;分區(qū)

  fdisk

  d 刪除一個(gè)分區(qū)

  n 新建一個(gè)分區(qū)

  w 保存退出

  q 不保存退出

  l 各分區(qū)類型對應(yīng)的System ID

  t 修改指定分區(qū)的System ID

  分區(qū)之后讓內(nèi)核重新讀取硬盤分區(qū)表的方法

  1、重啟系統(tǒng)

  2、RHEL5 上利用partprobe 實(shí)現(xiàn)

  REHL6 利用partx -a DEVICE 實(shí)現(xiàn)

  第二步:格式化分區(qū),創(chuàng)建文件系統(tǒng)

  mkfs -t fstype /dev/part = mke2fs -t fstype /dev/part

  要點(diǎn):1、文件系統(tǒng)必須被內(nèi)核支持才能使用,即內(nèi)核有相應(yīng)的內(nèi)核模塊,或者已經(jīng)

  帆正襪將之整合進(jìn)內(nèi)核;

  2、要有相應(yīng)文件系統(tǒng)創(chuàng)建工具,這通常是mkfs.fstype

  mke2fs -t {ext2|ext3|ext4}

  -b {1024|2023|4096}:塊大小

  塊大小取決CPU對內(nèi)存頁框大小的支持,x86系統(tǒng)默認(rèn)頁框大小為4K;

  -L label: 設(shè)定卷標(biāo)

  -m #: 預(yù)留給管理使用的塊所占據(jù)態(tài)激總體空間的比例;

  -r #: 預(yù)留給管理使用的塊的`個(gè)數(shù);

  -E: 設(shè)定文件系統(tǒng)的擴(kuò)展屬性;

  tune2fs

  -l: 顯示文件系統(tǒng)超級(jí)塊信息;

  -L label:重新設(shè)定卷標(biāo);

  -m #: 調(diào)整預(yù)留給管理使用的塊所占據(jù)總體空間的比例;

  -r #: 調(diào)整預(yù)留給管理使用的塊個(gè)數(shù);

  -o:設(shè)定掛載默認(rèn)選項(xiàng)

  -O: 設(shè)定文件系統(tǒng)默認(rèn)特性

  -E: 調(diào)整文件系統(tǒng)的擴(kuò)展屬性

  blkid DEVICE 顯示設(shè)備的UUID、文件系統(tǒng)類型及卷標(biāo)

  第三步 掛載

  mount DEVICE MOUNT_POINT

  mount LABEL=”卷標(biāo)” MOUNT_POINT

  mount UUID=”UUID” MOUNT_POINT

  掛載之后,原有數(shù)據(jù)的會(huì)被隱藏,因此不能掛載到系統(tǒng)常用目錄上;

  卸載之時(shí),要確保沒有進(jìn)程正在訪問掛載的清宏設(shè)備;否則,無法卸載;

  -o 用于指定掛在選項(xiàng)。

  ro: 只讀掛載;

  rw: 讀寫,默認(rèn)即為讀寫;

  noatime: 關(guān)閉 更新 訪問時(shí)間;

  auto: 是否能夠由“mount -a”掛載;

  defaults:相當(dāng)于rw, suid, dev, exec, auto, nouser, async, and relatime

  sync: 同步寫入

  async:異步寫入

  dev:

  remount: 重新掛載

  loop: 本地回環(huán)設(shè)備;

  -n 掛在系統(tǒng)時(shí),不更新設(shè)備文件

  -r 只讀掛載,相當(dāng)于“-o ro”

  free 查看內(nèi)存大小

  -m: 空間大小換算為MB

如何實(shí)現(xiàn)linux下多線程之間的互斥與同步

Linux設(shè)備驅(qū)動(dòng)中必須解決的一個(gè)問題是多個(gè)進(jìn)程對共享資源的并發(fā)訪問,并發(fā)訪問會(huì)導(dǎo)致競態(tài),linux提供了多種解決競態(tài)問題的方式,這些方式適合不同的應(yīng)用場景。

Linux內(nèi)核是多進(jìn)程、多線程的操作系統(tǒng),它提供了相當(dāng)完整的內(nèi)核同步方法。內(nèi)核同步方法列表如下:

中斷屏蔽

原子操作

自旋鎖

讀寫自旋鎖

順序鎖

信號(hào)量

讀寫信號(hào)量

BKL(大內(nèi)核鎖)

Seq鎖

一、并發(fā)與競態(tài):

定義:

并發(fā)(concurrency)指的是多個(gè)執(zhí)行單元同時(shí)、并行被執(zhí)行,而并發(fā)的執(zhí)行單元對共享資源(硬件資源和軟件上的全局變量、靜態(tài)變量等)的訪問則很容易導(dǎo)致競態(tài)(race conditions)。

在linux中,主要的競態(tài)發(fā)生在如下幾種情況:

1、對稱多處理器歷辯埋(P)多個(gè)CPU

特點(diǎn)是多個(gè)CPU使用共同的系統(tǒng)總線,因此可訪問共同的外設(shè)和存儲(chǔ)器。

2、單CPU內(nèi)進(jìn)程與搶占它的進(jìn)程

3、中斷(硬中斷、軟中斷、Tasklet、底半部)與進(jìn)程之間

只要并發(fā)的多個(gè)執(zhí)行單元存在對共享資源的訪問,競態(tài)就有可能發(fā)生。

如果中斷處理程序訪問進(jìn)程正在訪問的資源,則競態(tài)也會(huì)會(huì)發(fā)生。

多個(gè)中斷之間本身也可能引起并發(fā)而導(dǎo)致競態(tài)(中斷被更高優(yōu)先級(jí)的中斷打斷)。

解決競態(tài)問題的途徑是保證對共享資源的互斥訪問,所謂互斥訪問就是指一個(gè)執(zhí)行單元在訪問共享資源的時(shí)候,其他的執(zhí)行單元都被禁止訪問。

訪問共享資源的代碼區(qū)域被稱為臨界區(qū),臨界區(qū)需要以某種互斥機(jī)制加以保護(hù),中斷屏蔽,原子操作,自旋鎖,和信號(hào)量都是linux設(shè)備驅(qū)動(dòng)中可采用的互斥途徑。

臨界區(qū)和競爭條件:

所謂臨界區(qū)(critical regions)就是訪問和操作共享數(shù)據(jù)的代碼段,為了避免在臨界區(qū)中并發(fā)訪問,編程者必須保證這些代碼原子地執(zhí)行——也就是說,代碼在執(zhí)行結(jié)束前不可被打斷,就如同整個(gè)臨界區(qū)是一個(gè)不可分割的指令一樣,如果兩個(gè)執(zhí)行線程有可能處于同一個(gè)臨界區(qū)中,那么就是程序包含一個(gè)bug,如果這種情況發(fā)生了,我們就稱之為競爭條件(race conditions),避免并發(fā)和防止競爭條件被稱為同步。

死鎖:

死鎖的產(chǎn)生需要一定條件:要有一個(gè)或多個(gè)執(zhí)行線程和一個(gè)或多個(gè)資源,每個(gè)線程都在等待其中的一個(gè)資源,但所有的資源都已經(jīng)被占用了,所有線程都在相互等待,但它們永遠(yuǎn)不會(huì)釋放已經(jīng)占有的資源,于是任何線程都無法繼續(xù),這便意味著死鎖的發(fā)生。

二、中斷屏蔽

在單CPU范圍內(nèi)避免競態(tài)的一種簡單方法是在進(jìn)入臨界區(qū)之前屏蔽系統(tǒng)的中斷。

由于linux內(nèi)核的進(jìn)程調(diào)度等操作都依賴中斷來實(shí)現(xiàn),內(nèi)核搶占進(jìn)程之間的并發(fā)也就得以避免了。

中斷屏蔽的使用方法:

local_irq_disable()//屏蔽中斷

//臨界區(qū)

local_irq_enable()//灶念開中斷

特點(diǎn):

由于linux系統(tǒng)的異步IO,進(jìn)程調(diào)度等很多重要操作都依賴于中斷,在屏蔽中斷期間所有的中斷都無法得到處理,因此長時(shí)間的屏蔽是很危險(xiǎn)的,有可能造成數(shù)據(jù)丟失甚至系統(tǒng)崩潰,這就要求在屏蔽中斷之后,當(dāng)前的內(nèi)核執(zhí)行路徑應(yīng)當(dāng)盡快地執(zhí)行完臨界區(qū)的代碼。

中斷屏蔽只能禁止本CPU內(nèi)的中斷,因此,并不能解決多CPU引發(fā)的競態(tài),所以單獨(dú)使用中斷屏蔽并不是一個(gè)值得推薦的避免競態(tài)的方法,它一般和自旋鎖配合使用。

三、原子操作

定義:原子操作指的是在執(zhí)行過程中不會(huì)被別的代碼路徑所中斷的操作。

(原子原本指的是不可分割的微粒,所以原子操作也就是不能夠被分割的指令)

(它保證指令以“原子”的方式執(zhí)行而不能被打斷)

原子操作是不可分割的,在執(zhí)行完畢不會(huì)被任何其它任務(wù)或事件中斷。在單處理器系統(tǒng)(UniProcessor)中,能夠在單條指令中完成的操作都可以認(rèn)為是” 原子操作”,因?yàn)橹袛嘀荒馨l(fā)生于指令之間。這也是某些CPU指令系統(tǒng)中引入了test_and_set、test_and_clear等指令用于臨界資源互斥的原因。但是,在對稱多處理器(Symmetric Multi-Processor)結(jié)構(gòu)中就不同了,由于系統(tǒng)中有多個(gè)處理器在獨(dú)立地運(yùn)行,即使能在單條指令中完成的操作也有可能受到干擾。我們以decl (遞減指令)為例,這是一個(gè)典型的”讀-改-肢螞寫”過程,涉及兩次內(nèi)存訪問。

通俗理解:

原子操作,顧名思義,就是說像原子一樣不可再細(xì)分。一個(gè)操作是原子操作,意思就是說這個(gè)操作是以原子的方式被執(zhí)行,要一口氣執(zhí)行完,執(zhí)行過程不能夠被OS的其他行為打斷,是一個(gè)整體的過程,在其執(zhí)行過程中,OS的其它行為是插不進(jìn)來的。

分類:linux內(nèi)核提供了一系列函數(shù)來實(shí)現(xiàn)內(nèi)核中的原子操作,分為整型原子操作和位原子操作,共同點(diǎn)是:在任何情況下操作都是原子的,內(nèi)核代碼可以安全的調(diào)用它們而不被打斷。

原子整數(shù)操作:

針對整數(shù)的原子操作只能對atomic_t類型的數(shù)據(jù)進(jìn)行處理,在這里之所以引入了一個(gè)特殊的數(shù)據(jù)類型,而沒有直接使用C語言的int型,主要是出于兩個(gè)原因:

之一、讓原子函數(shù)只接受atomic_t類型的操作數(shù),可以確保原子操作只與這種特殊類型數(shù)據(jù)一起使用,同時(shí),這也確保了該類型的數(shù)據(jù)不會(huì)被傳遞給其它任何非原子函數(shù);

第二、使用atomic_t類型確保編譯器不對相應(yīng)的值進(jìn)行訪問優(yōu)化——這點(diǎn)使得原子操作最終接收到正確的內(nèi)存地址,而不是一個(gè)別名,最后就是在不同體系結(jié)構(gòu)上實(shí)現(xiàn)原子操作的時(shí)候,使用atomic_t可以屏蔽其間的差異。

原子整數(shù)操作最常見的用途就是實(shí)現(xiàn)計(jì)數(shù)器。

另一點(diǎn)需要說明原子操作只能保證操作是原子的,要么完成,要么不完成,不會(huì)有操作一半的可能,但原子操作并不能保證操作的順序性,即它不能保證兩個(gè)操作是按某個(gè)順序完成的。如果要保證原子操作的順序性,請使用內(nèi)存屏障指令。

atomic_t和ATOMIC_INIT(i)定義

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i) { (i) }

在你編寫代碼的時(shí)候,能使用原子操作的時(shí)候,就盡量不要使用復(fù)雜的加鎖機(jī)制,對多數(shù)體系結(jié)構(gòu)來講,原子操作與更復(fù)雜的同步方法相比較,給系統(tǒng)帶來的開銷小,對高速緩存行的影響也小,但是,對于那些有高性能要求的代碼,對多種同步方法進(jìn)行測試比較,不失為一種明智的作法。

原子位操作:

針對位這一級(jí)數(shù)據(jù)進(jìn)行操作的函數(shù),是對普通的內(nèi)存地址進(jìn)行操作的。它的參數(shù)是一個(gè)指針和一個(gè)位號(hào)。

為方便其間,內(nèi)核還提供了一組與上述操作對應(yīng)的非原子位函數(shù),非原子位函數(shù)與原子位函數(shù)的操作完全相同,但是,前者不保證原子性,且其名字前綴多兩個(gè)下劃線。例如,與test_bit()對應(yīng)的非原子形式是_test_bit(),如果你不需要原子性操作(比如,如果你已經(jīng)用鎖保護(hù)了自己的數(shù)據(jù)),那么這些非原子的位函數(shù)相比原子的位函數(shù)可能會(huì)執(zhí)行得更快些。

四、自旋鎖

自旋鎖的引入:

如 果每個(gè)臨界區(qū)都能像增加變量這樣簡單就好了,可惜現(xiàn)實(shí)不是這樣,而是臨界區(qū)可以跨越多個(gè)函數(shù),例如:先得從一個(gè)數(shù)據(jù)結(jié)果中移出數(shù)據(jù),對其進(jìn)行格式轉(zhuǎn)換和解 析,最后再把它加入到另一個(gè)數(shù)據(jù)結(jié)構(gòu)中,整個(gè)執(zhí)行過程必須是原子的,在數(shù)據(jù)被更新完畢之前,不能有其他代碼讀取這些數(shù)據(jù),顯然,簡單的原子操作是無能為力 的(在單處理器系統(tǒng)(UniProcessor)中,能夠在單條指令中完成的操作都可以認(rèn)為是” 原子操作”,因?yàn)橹袛嘀荒馨l(fā)生于指令之間),這就需要使用更為復(fù)雜的同步方法——鎖來提供保護(hù)。

自旋鎖的介紹:

Linux內(nèi)核中最常見的鎖是自旋鎖(spin lock),自旋鎖最多只能被一個(gè)可執(zhí)行線程持有,如果一個(gè)執(zhí)行線程試圖獲得一個(gè)被爭用(已經(jīng)被持有)的自旋鎖,那么該線程就會(huì)一直進(jìn)行忙循環(huán)—旋轉(zhuǎn)—等待鎖重新可用,要是鎖未被爭用,請求鎖的執(zhí)行線程便能立刻得到它,繼續(xù)執(zhí)行,在任意時(shí)間,自旋鎖都可以防止多于一個(gè)的執(zhí)行線程同時(shí)進(jìn)入理解區(qū),注意同一個(gè)鎖可以用在多個(gè)位置—例如,對于給定數(shù)據(jù)的所有訪問都可以得到保護(hù)和同步。

一個(gè)被爭用的自旋鎖使得請求它的線程在等待鎖重新可用時(shí)自旋(特別浪費(fèi)處理器時(shí)間),所以自旋鎖不應(yīng)該被長時(shí)間持有,事實(shí)上,這點(diǎn)正是使用自旋鎖的初衷,在短期間內(nèi)進(jìn)行輕量級(jí)加鎖,還可以采取另外的方式來處理對鎖的爭用:讓請求線程睡眠,直到鎖重新可用時(shí)再喚醒它,這樣處理器就不必循環(huán)等待,可以去執(zhí)行其他代碼,這也會(huì)帶來一定的開銷——這里有兩次明顯的上下文切換, 被阻塞的線程要換出和換入。因此,持有自旋鎖的時(shí)間更好小于完成兩次上下文切換的耗時(shí),當(dāng)然我們大多數(shù)人不會(huì)無聊到去測量上下文切換的耗時(shí),所以我們讓持 有自旋鎖的時(shí)間應(yīng)盡可能的短就可以了,信號(hào)量可以提供上述第二種機(jī)制,它使得在發(fā)生爭用時(shí),等待的線程能投入睡眠,而不是旋轉(zhuǎn)。

自旋鎖可以使用在中斷處理程序中(此處不能使用信號(hào)量,因?yàn)樗鼈儠?huì)導(dǎo)致睡眠),在中斷處理程序中使用自旋鎖時(shí),一定要在獲取鎖之前,首先禁止本地中斷(在 當(dāng)前處理器上的中斷請求),否則,中斷處理程序就會(huì)打斷正持有鎖的內(nèi)核代碼,有可能會(huì)試圖去爭用這個(gè)已經(jīng)持有的自旋鎖,這樣以來,中斷處理程序就會(huì)自旋, 等待該鎖重新可用,但是鎖的持有者在這個(gè)中斷處理程序執(zhí)行完畢前不可能運(yùn)行,這正是我們在前一章節(jié)中提到的雙重請求死鎖,注意,需要關(guān)閉的只是當(dāng)前處理器上的中斷,如果中斷發(fā)生在不同的處理器上,即使中斷處理程序在同一鎖上自旋,也不會(huì)妨礙鎖的持有者(在不同處理器上)最終釋放鎖。

自旋鎖的簡單理解:

理解自旋鎖最簡單的方法是把它作為一個(gè)變量看待,該變量把一個(gè)臨界區(qū)或者標(biāo)記為“我當(dāng)前正在運(yùn)行,請稍等一會(huì)”或者標(biāo)記為“我當(dāng)前不在運(yùn)行,可以被使用”。如果A執(zhí)行單元首先進(jìn)入例程,它將持有自旋鎖,當(dāng)B執(zhí)行單元試圖進(jìn)入同一個(gè)例程時(shí),將獲知自旋鎖已被持有,需等到A執(zhí)行單元釋放后才能進(jìn)入。

自旋鎖的API函數(shù):

其實(shí)介紹的幾種信號(hào)量和互斥機(jī)制,其底層源碼都是使用自旋鎖,可以理解為自旋鎖的再包裝。所以從這里就可以理解為什么自旋鎖通常可以提供比信號(hào)量更高的性能。

自旋鎖是一個(gè)互斥設(shè)備,他只能會(huì)兩個(gè)值:“鎖定”和“解鎖”。它通常實(shí)現(xiàn)為某個(gè)整數(shù)之中的單個(gè)位。

“測試并設(shè)置”的操作必須以原子方式完成。

任何時(shí)候,只要內(nèi)核代碼擁有自旋鎖,在相關(guān)CPU上的搶占就會(huì)被禁止。

適用于自旋鎖的核心規(guī)則:

(1)任何擁有自旋鎖的代碼都必須使原子的,除服務(wù)中斷外(某些情況下也不能放棄CPU,如中斷服務(wù)也要獲得自旋鎖。為了避免這種鎖陷阱,需要在擁有自旋鎖時(shí)禁止中斷),不能放棄CPU(如休眠,休眠可發(fā)生在許多無法預(yù)期的地方)。否則CPU將有可能永遠(yuǎn)自旋下去(死機(jī))。

(2)擁有自旋鎖的時(shí)間越短越好。

需 要強(qiáng)調(diào)的是,自旋鎖別設(shè)計(jì)用于多處理器的同步機(jī)制,對于單處理器(對于單處理器并且不可搶占的內(nèi)核來說,自旋鎖什么也不作),內(nèi)核在編譯時(shí)不會(huì)引入自旋鎖 機(jī)制,對于可搶占的內(nèi)核,它僅僅被用于設(shè)置內(nèi)核的搶占機(jī)制是否開啟的一個(gè)開關(guān),也就是說加鎖和解鎖實(shí)際變成了禁止或開啟內(nèi)核搶占功能。如果內(nèi)核不支持搶 占,那么自旋鎖根本就不會(huì)編譯到內(nèi)核中。

內(nèi)核中使用spinlock_t類型來表示自旋鎖,它定義在:

typedef struct {

raw_spinlock_t raw_lock;

#if defined(CONFIG_PREEMPT) && defined(CONFIG_P)

unsigned int break_lock;

#endif

} spinlock_t;

對于不支持P的內(nèi)核來說,struct raw_spinlock_t什么也沒有,是一個(gè)空結(jié)構(gòu)。對于支持多處理器的內(nèi)核來說,struct raw_spinlock_t定義為

typedef struct {

unsigned int slock;

} raw_spinlock_t;

slock表示了自旋鎖的狀態(tài),“1”表示自旋鎖處于解鎖狀態(tài)(UNLOCK),“0”表示自旋鎖處于上鎖狀態(tài)(LOCKED)。

break_lock表示當(dāng)前是否由進(jìn)程在等待自旋鎖,顯然,它只有在支持搶占的P內(nèi)核上才起作用。

自旋鎖的實(shí)現(xiàn)是一個(gè)復(fù)雜的過程,說它復(fù)雜不是因?yàn)樾枰嗌俅a或邏輯來實(shí)現(xiàn)它,其實(shí)它的實(shí)現(xiàn)代碼很少。自旋鎖的實(shí)現(xiàn)跟體系結(jié)構(gòu)關(guān)系密切,核心代碼基本也是由匯編語言寫成,與體協(xié)結(jié)構(gòu)相關(guān)的核心代碼都放在相關(guān)的目錄下,比如。對于我們驅(qū)動(dòng)程序開發(fā)人員來說,我們沒有必要了解這么spinlock的內(nèi)部細(xì)節(jié),如果你對它感興趣,請參考閱讀Linux內(nèi)核源代碼。對于我們驅(qū)動(dòng)的spinlock接口,我們只需包括頭文件。在我們詳細(xì)的介紹spinlock的API之前,我們先來看看自旋鎖的一個(gè)基本使用格式:

#include

spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock(&lock);

….

spin_unlock(&lock);

從使用上來說,spinlock的API還很簡單的,一般我們會(huì)用的的API如下表,其實(shí)它們都是定義在中的宏接口,真正的實(shí)現(xiàn)在中

#include

SPIN_LOCK_UNLOCKED

DEFINE_SPINLOCK

spin_lock_init( spinlock_t *)

spin_lock(spinlock_t *)

spin_unlock(spinlock_t *)

spin_lock_irq(spinlock_t *)

spin_unlock_irq(spinlock_t *)

spin_lock_irqsace(spinlock_t *,unsigned long flags)

spin_unlock_irqsace(spinlock_t *, unsigned long flags)

spin_trylock(spinlock_t *)

spin_is_locked(spinlock_t *)

? 初始化

spinlock有兩種初始化形式,一種是靜態(tài)初始化,一種是動(dòng)態(tài)初始化。對于靜態(tài)的spinlock對象,我們用 SPIN_LOCK_UNLOCKED來初始化,它是一個(gè)宏。當(dāng)然,我們也可以把聲明spinlock和初始化它放在一起做,這就是 DEFINE_SPINLOCK宏的工作,因此,下面的兩行代碼是等價(jià)的。

DEFINE_SPINLOCK (lock);

spinlock_t lock = SPIN_LOCK_UNLOCKED;

spin_lock_init 函數(shù)一般用來初始化動(dòng)態(tài)創(chuàng)建的spinlock_t對象,它的參數(shù)是一個(gè)指向spinlock_t對象的指針。當(dāng)然,它也可以初始化一個(gè)靜態(tài)的沒有初始化的spinlock_t對象。

spinlock_t *lock

……

spin_lock_init(lock);

? 獲取鎖

內(nèi)核提供了三個(gè)函數(shù)用于獲取一個(gè)自旋鎖。

spin_lock:獲取指定的自旋鎖。

spin_lock_irq:禁止本地中斷并獲取自旋鎖。

spin_lock_irqsace:保存本地中斷狀態(tài),禁止本地中斷并獲取自旋鎖,返回本地中斷狀態(tài)。

自旋鎖是可以使用在中斷處理程序中的,這時(shí)需要使用具有關(guān)閉本地中斷功能的函數(shù),我們推薦使用 spin_lock_irqsave,因?yàn)樗鼤?huì)保存加鎖前的中斷標(biāo)志,這樣就會(huì)正確恢復(fù)解鎖時(shí)的中斷標(biāo)志。如果spin_lock_irq在加鎖時(shí)中斷是關(guān)閉的,那么在解鎖時(shí)就會(huì)錯(cuò)誤的開啟中斷。

另外兩個(gè)同自旋鎖獲取相關(guān)的函數(shù)是:

spin_trylock():嘗試獲取自旋鎖,如果獲取失敗則立即返回非0值,否則返回0。

spin_is_locked():判斷指定的自旋鎖是否已經(jīng)被獲取了。如果是則返回非0,否則,返回0。

? 釋放鎖

同獲取鎖相對應(yīng),內(nèi)核提供了三個(gè)相對的函數(shù)來釋放自旋鎖。

spin_unlock:釋放指定的自旋鎖。

spin_unlock_irq:釋放自旋鎖并激活本地中斷。

spin_unlock_irqsave:釋放自旋鎖,并恢復(fù)保存的本地中斷狀態(tài)。

五、讀寫自旋鎖

如 果臨界區(qū)保護(hù)的數(shù)據(jù)是可讀可寫的,那么只要沒有寫操作,對于讀是可以支持并發(fā)操作的。對于這種只要求寫操作是互斥的需求,如果還是使用自旋鎖顯然是無法滿 足這個(gè)要求(對于讀操作實(shí)在是太浪費(fèi)了)。為此內(nèi)核提供了另一種鎖-讀寫自旋鎖,讀自旋鎖也叫共享自旋鎖,寫自旋鎖也叫排他自旋鎖。

讀寫自旋鎖是一種比自旋鎖粒度更小的鎖機(jī)制,它保留了“自旋”的概念,但是在寫操作方面,只能最多有一個(gè)寫進(jìn)程,在讀操作方面,同時(shí)可以有多個(gè)讀執(zhí)行單元,當(dāng)然,讀和寫也不能同時(shí)進(jìn)行。

讀寫自旋鎖的使用也普通自旋鎖的使用很類似,首先要初始化讀寫自旋鎖對象:

// 靜態(tài)初始化

rwlock_t rwlock = RW_LOCK_UNLOCKED;

//動(dòng)態(tài)初始化

rwlock_t *rwlock;

rw_lock_init(rwlock);

在讀操作代碼里對共享數(shù)據(jù)獲取讀自旋鎖:

read_lock(&rwlock);

read_unlock(&rwlock);

在寫操作代碼里為共享數(shù)據(jù)獲取寫自旋鎖:

write_lock(&rwlock);

write_unlock(&rwlock);

需要注意的是,如果有大量的寫操作,會(huì)使寫操作自旋在寫自旋鎖上而處于寫?zhàn)囸I狀態(tài)(等待讀自旋鎖的全部釋放),因?yàn)樽x自旋鎖會(huì)自由的獲取讀自旋鎖。

讀寫自旋鎖的函數(shù)類似于普通自旋鎖,這里就不一一介紹了,我們把它列在下面的表中。

RW_LOCK_UNLOCKED

rw_lock_init(rwlock_t *)

read_lock(rwlock_t *)

read_unlock(rwlock_t *)

read_lock_irq(rwlock_t *)

read_unlock_irq(rwlock_t *)

read_lock_irqsave(rwlock_t *, unsigned long)

read_unlock_irqsave(rwlock_t *, unsigned long)

write_lock(rwlock_t *)

write_unlock(rwlock_t *)

write_lock_irq(rwlock_t *)

write_unlock_irq(rwlock_t *)

write_lock_irqsave(rwlock_t *, unsigned long)

write_unlock_irqsave(rwlock_t *, unsigned long)

rw_is_locked(rwlock_t *)

六、順序瑣

順序瑣(seqlock)是對讀寫鎖的一種優(yōu)化,若使用順序瑣,讀執(zhí)行單元絕不會(huì)被寫執(zhí)行單元阻塞,也就是說,讀執(zhí)行單元可以在寫執(zhí)行單元對被順序瑣保護(hù)的共享資源進(jìn)行寫操作時(shí)仍然可以繼續(xù)讀,而不必等待寫執(zhí)行單元完成寫操作,寫執(zhí)行單元也不需要等待所有讀執(zhí)行單元完成讀操作才去進(jìn)行寫操作。

但是,寫執(zhí)行單元與寫執(zhí)行單元之間仍然是互斥的,即如果有寫執(zhí)行單元在進(jìn)行寫操作,其它寫執(zhí)行單元必須自旋在哪里,直到寫執(zhí)行單元釋放了順序瑣。

如果讀執(zhí)行單元在讀操作期間,寫執(zhí)行單元已經(jīng)發(fā)生了寫操作,那么,讀執(zhí)行單元必須重新讀取數(shù)據(jù),以便確保得到的數(shù)據(jù)是完整的,這種鎖在讀寫同時(shí)進(jìn)行的概率比較小時(shí),性能是非常好的,而且它允許讀寫同時(shí)進(jìn)行,因而更大的提高了并發(fā)性,

注意,順序瑣由一個(gè)限制,就是它必須被保護(hù)的共享資源不含有指針,因?yàn)閷憟?zhí)行單元可能使得指針失效,但讀執(zhí)行單元如果正要訪問該指針,將導(dǎo)致Oops。

七、信號(hào)量

Linux中的信號(hào)量是一種睡眠鎖,如果有一個(gè)任務(wù)試圖獲得一個(gè)已經(jīng)被占用的信號(hào)量時(shí),信號(hào)量會(huì)將其推進(jìn)一個(gè)等待隊(duì)列,然后讓其睡眠,這時(shí)處理器能重獲自由,從而去執(zhí)行其它代碼,當(dāng)持有信號(hào)量的進(jìn)程將信號(hào)量釋放后,處于等待隊(duì)列中的哪個(gè)任務(wù)被喚醒,并獲得該信號(hào)量。

信號(hào)量,或旗標(biāo),就是我們在操作系統(tǒng)里學(xué)習(xí)的經(jīng)典的P/V原語操作。

P:如果信號(hào)量值大于0,則遞減信號(hào)量的值,程序繼續(xù)執(zhí)行,否則,睡眠等待信號(hào)量大于0。

V:遞增信號(hào)量的值,如果遞增的信號(hào)量的值大于0,則喚醒等待的進(jìn)程。

信號(hào)量的值確定了同時(shí)可以有多少個(gè)進(jìn)程可以同時(shí)進(jìn)入臨界區(qū),如果信號(hào)量的初始值始1,這信號(hào)量就是互斥信號(hào)量(MUTEX)。對于大于1的非0值信號(hào)量,也可稱為計(jì)數(shù)信號(hào)量(counting semaphore)。對于一般的驅(qū)動(dòng)程序使用的信號(hào)量都是互斥信號(hào)量。

類似于自旋鎖,信號(hào)量的實(shí)現(xiàn)也與體系結(jié)構(gòu)密切相關(guān),具體的實(shí)現(xiàn)定義在頭文件中,對于x86_32系統(tǒng)來說,它的定義如下:

struct semaphore {

atomic_t count;

int sleepers;

wait_queue_head_t wait;

};

信號(hào)量的初始值count是atomic_t類型的,這是一個(gè)原子操作類型,它也是一個(gè)內(nèi)核同步技術(shù),可見信號(hào)量是基于原子操作的。我們會(huì)在后面原子操作部分對原子操作做詳細(xì)介紹。

信號(hào)量的使用類似于自旋鎖,包括創(chuàng)建、獲取和釋放。我們還是來先展示信號(hào)量的基本使用形式:

static DECLARE_MUTEX(my_sem);

……

if (down_interruptible(&my_sem))

{

return -ERESTARTSYS;

}

……

up(&my_sem)

Linux內(nèi)核中的信號(hào)量函數(shù)接口如下:

static DECLARE_SEMAPHORE_GENERIC(name, count);

static DECLARE_MUTEX(name);

seam_init(struct semaphore *, int);

init_MUTEX(struct semaphore *);

init_MUTEX_LOCKED(struct semaphore *)

down_interruptible(struct semaphore *);

down(struct semaphore *)

down_trylock(struct semaphore *)

up(struct semaphore *)

? 初始化信號(hào)量

信號(hào)量的初始化包括靜態(tài)初始化和動(dòng)態(tài)初始化。靜態(tài)初始化用于靜態(tài)的聲明并初始化信號(hào)量。

static DECLARE_SEMAPHORE_GENERIC(name, count);

static DECLARE_MUTEX(name);

對于動(dòng)態(tài)聲明或創(chuàng)建的信號(hào)量,可以使用如下函數(shù)進(jìn)行初始化:

seam_init(sem, count);

init_MUTEX(sem);

init_MUTEX_LOCKED(struct semaphore *)

顯然,帶有MUTEX的函數(shù)始初始化互斥信號(hào)量。LOCKED則初始化信號(hào)量為鎖狀態(tài)。

? 使用信號(hào)量

信號(hào)量初始化完成后我們就可以使用它了

down_interruptible(struct semaphore *);

down(struct semaphore *)

down_trylock(struct semaphore *)

up(struct semaphore *)

down函數(shù)會(huì)嘗試獲取指定的信號(hào)量,如果信號(hào)量已經(jīng)被使用了,則進(jìn)程進(jìn)入不可中斷的睡眠狀態(tài)。down_interruptible則會(huì)使進(jìn)程進(jìn)入可中斷的睡眠狀態(tài)。關(guān)于進(jìn)程狀態(tài)的詳細(xì)細(xì)節(jié),我們在內(nèi)核的進(jìn)程管理里在做詳細(xì)介紹。

down_trylock嘗試獲取信號(hào)量, 如果獲取成功則返回0,失敗則會(huì)立即返回非0。

當(dāng)退出臨界區(qū)時(shí)使用up函數(shù)釋放信號(hào)量,如果信號(hào)量上的睡眠隊(duì)列不為空,則喚醒其中一個(gè)等待進(jìn)程。

八、讀寫信號(hào)量

類似于自旋鎖,信號(hào)量也有讀寫信號(hào)量。讀寫信號(hào)量API定義在頭文件中,它的定義其實(shí)也是體系結(jié)構(gòu)相關(guān)的,因此具體實(shí)現(xiàn)定義在頭文件中,以下是x86的例子:

struct rw_semaphore {

signed long count;

spinlock_t wait_lock;

struct list_head wait_list;

};

linux 異步讀寫的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于linux 異步讀寫,高效穩(wěn)定!探究Linux異步讀寫機(jī)制,linux磁盤格式化與管理知識(shí)點(diǎn)總結(jié),如何實(shí)現(xiàn)linux下多線程之間的互斥與同步的信息別忘了在本站進(jìn)行查找喔。

香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗(yàn)。專業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。


本文題目:高效穩(wěn)定!探究Linux異步讀寫機(jī)制(linux異步讀寫)
分享路徑:http://m.5511xx.com/article/dhicgsh.html