2014-09-23 122 views
16

我有this code用於在Linux中讀取串口,但我不知道在讀取串行端口時阻塞與非阻塞之間有什麼區別,哪一個在哪種情況下更好?Linux阻塞與非阻塞串行讀取

+4

它完全取決於你的應用程序的體系結構。阻止更簡單,但阻止。非阻塞需要稍微更多的編碼,但可以讓您在同一時間完成另一項任務。 – 2014-09-23 13:26:49

回答

41

你提到的代碼是國際海事組織編碼差,並評論。該代碼不符合POSIX實用程序的可移植性,如Setting Terminal Modes ProperlySerial Programming Guide for POSIX Operating Systems中所述。該代碼沒有提及它使用非規範(又名原始)模式,並重復使用「阻塞」和「非阻塞」術語來描述屬性的屬性。

「阻塞」與「非阻塞」讀取的常規定義基於「何時」讀取調用將返回到您的程序(並繼續執行下一條語句)以及程序中是否存儲有數據讀取緩衝區。阻塞讀取是默認模式,除非通過使用O_NONBLOCK或O_NDELAY選項打開串行端口來請求非阻塞。

典型模式
對於文本的阻擋canonical read調用一個串口,一個線(又名記錄)將永遠在提供的緩衝區返回(除非發生錯誤)。只要需要接收和處理行終止字符,讀取調用就會阻塞(即暫停執行程序)。

串行端口的非阻塞規範讀取調用將始終返回「立即」。讀取可能會或可能不會返回任何數據。
如果(自上次讀取調用以來)至少有一行文本已被接收並存儲在系統緩衝區中,則最早的行將從系統緩衝區中移除並複製到程序的緩衝區中。返回碼將指示數據長度。
如果(自上次讀取調用以來)行終止字符未被接收和處理,則沒有(完整)行文本可用。 read()將返回EAGAIN錯誤(即設置爲EAGAIN的-1返回碼和errno)。然後,您的程序可以執行一些計算,或從另一個設備請求I/O,或延遲/休眠。經過任意延遲或通過poll()select()通知,您的程序可以重試read()

非標準模式
當串行端口被配置用於非規範模式,則termios的c_cc中陣列元件VMINVTIME應被用於控制「阻塞」 ,但是這要求端口以默認的阻塞模式打開,即不要指定O_NONBLOCK打開選項。否則O_NONBLOCK將優先於VMIN和VTIME規範,閱讀()將設置錯誤號爲EAGAIN並立即返回-1而不是0時,有沒有可用數據。 (這是在最近的Linux 3.x內核中觀察到的行爲;較舊的2.6.x內核行爲可能不同。)

的termios的手冊頁介紹(c_cc中數組索引)VMIN作爲「最小數目爲非典型讀取的字符」,和(c_cc中數組索引)VTIME作爲「超時非標準讀取的時間爲十分位「
VMIN應該由你的程序,以適應預期的典型的消息或數據報的長度和/或最小尺寸來調節數據到每讀()檢索&過程。
VTIME應由程序進行調整,以適應預期的串行數據的典型突發或到達率和/或等待數據或數據的最長時間。

VMIN and VTIME值相互作用以確定讀取時應返回的標準;它們的確切含義取決於它們中的哪一個是非零的。有四種可能的情況。
This web page解釋它爲:

  • VMIN = 0和VTIME = 0

    這是一個完全的非阻擋讀 - 呼叫是立即滿足直接來自駕駛員的輸入隊列。如果數據可用,則將其傳輸到呼叫者的緩衝區,最多爲nbytes並返回。否則,立即返回零以指示「無數據」。我們會注意到這是串口的「輪詢」,而且幾乎總是一個壞主意。如果反覆進行,它可能會消耗大量的處理器時間,效率非常低。除非你真的,真的知道你在做什麼,否則不要使用這種模式。

  • VMIN = 0和VTIME> 0

    這是一個純粹賦時讀取。如果數據在輸入隊列中可用,則將其傳輸到主叫方的緩衝區,最大數量爲nbytes,並立即返回給主叫方。否則,驅動程序阻塞直到數據到達,或者VTIME十分之一從通話開始到期。如果定時器在沒有數據的情況下到期,則返回零。單個字節足以滿足此讀取調用,但如果輸入隊列中有更多可用字段,則它將返回給調用者。請注意,這是一個整體計時器,而不是一個字符。

  • VMIN> 0和VTIME> 0

    的read()被滿足時或者VMIN字符已被傳送到呼叫者的緩衝器,或者當VTIME十分之字符之間到期。由於此定時器在第一個字符到達之前未啓動,因此如果串行線路空閒,此呼叫可能無限期地阻塞。這是最常見的操作模式,我們認爲VTIME是一個字符間超時,而不是一個整體。這個調用不應該返回零字節讀取。

(以我的經驗,作爲標榜VMIN>0 and VTIME>0模式完全不是那麼回事。計時器似乎是一個非常短的時間間隔,遠低於1/10秒。我沒有看到它在ARM上使用2.6,而在x86上使用Linux 3.13。在快速波特率(115200)下,VMIN = 1且VTIME = 1時,read()有時會返回10個或更多字節。但更經常的是,無論VTIME的值是多少個字節的部分讀取。也許這種破碎是首選/希望?最小0.1秒消息分離是簡單地在現代快速波特率太長(和不實用的)。)

  • VMIN> 0且VTIME = 0

    這是被滿足,只有當在一個計數讀最少的VMIN字符已被傳輸到調用者的緩衝區 - 不涉及任何時間組件。這個讀取可以通過驅動程序的輸入隊列(呼叫可以立即返回)或等待新數據到達來滿足:在這方面,呼叫可以無限期地阻止。如果nbytes小於VMIN,我們認爲它是未定義的行爲。

該代碼你提到提供配置 「非阻塞」 模式作爲VMIN = 0和VTIME = 5。這不會導致read()像非阻塞規範讀取那樣立即返回;使用該代碼時,read()應該始終等待至少半秒鐘才返回。傳統的「非阻塞」定義是,你的調用程序在系統調用期間不被搶佔,並立即得到控制(幾乎)。 要獲得(無條件和立即返回)(對於非規範讀取),請設置VMIN = 0和VTIME = 0。

+0

很好的解釋,但哇。誠然,這是一個非常凌亂的合同,相比[Windows有什麼](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363190%28v=vs.85%29.aspx) – 2014-09-24 01:20:26

+7

代碼在POSIX之前數年,所以它不匹配就不足爲奇了。 – wallyk 2015-02-18 01:00:48

+0

如果'O_NONBLOCK'不是在非規範模式中指定的,那麼指定'O_NONBLOCK'對規範模式有什麼作用? – CMCDragonkai 2017-01-21 01:05:40