簡體   English   中英

帶有GCD的異步NSStream I / O

[英]Asynchronous NSStream I/O with GCD

我正在使用從中接收數據的外部設備。 我想在一個線程中異步處理其數據讀/寫隊列。

我基本上可以正常工作:有一個類可以簡單地管理兩個流,使用NSStreamDelegate響應傳入的數據,以及響應NSStreamEventHasSpaceAvailable來發送在較早發送失敗后在緩沖區中等待的數據。

此類稱為SerialIOStream ,它不知道線程或GCD隊列。 相反,它的用戶稱為DeviceCommunicator ,它使用一個GCD隊列在其中初始化SerialIOStream類(該類依次創建和打開流,並在當前運行循環中對其進行調度):

ioQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(ioQueue, ^{ 
    ioStreams = [[SerialIOStream alloc] initWithPath:[@"/dev/tty.mydevice"]];
    [[NSRunLoop currentRunLoop] run];
});

這樣, SerialIOStreamstream:handleEvent:方法顯然在該GCD隊列中運行。

但是,這引起一些問題。 我相信我會遇到並發問題,甚至崩潰,主要是在將待處理數據饋送到輸出流時。 代碼中有一個關鍵部分,我將緩沖的輸出數據傳遞到流,然后查看流中實際接受了多少數據,然后從緩沖區中刪除該部分:

NSInteger n = self.dataToWrite.length;
if (n > 0 && stream.hasSpaceAvailable) {
    NSInteger bytesWritten = [stream write:self.dataToWrite.bytes maxLength:n];
    if (bytesWritten > 0) {
        [self.dataToWrite replaceBytesInRange:NSMakeRange(0, bytesWritten) withBytes:NULL length:0];
    }
}

上面的代碼可以從兩個地方調用:

  1. 來自用戶( DeviceCommunicator
  2. 在被告知輸出流中有空間之后,從本地stream:handleEvent:方法。

它們可能(肯定是)在單獨的線程中運行,因此我需要確保它們不會同時運行此代碼。

我以為我可以通過在發送新數據時在DeviceCommunicator使用以下代碼來解決此問題:

dispatch_async (ioQueue, ^{
    [ioStreams writeData:data];
});

writeData將數據添加到dataToWrite ,請參見上文,然后運行以上代碼將其發送到流。)

但是,這不起作用,顯然是因為ioQueue是並發隊列,它可能決定使用任何可用線程,因此當DeviceCommunicator調用writeData時導致爭用條件,同時stream:handleEvent:也對其進行了調用stream:handleEvent: ,在單獨的線程上。

因此,我想我在對GCD隊列的明顯誤解中混入了對線程的期望(我對此更加熟悉了)。

我該如何正確解決呢?

我可以添加一個NSLock,用它來保護writeData方法,並且我相信那可以解決那個問題。 但是我不太確定應該使用GCD的方式-我覺得那會很混亂。

我是否應該使用自己的串行隊列來創建一個單獨的類,以訪問和修改dataToWrite緩沖區?

我仍在嘗試掌握與此有關的模式。 不知何故,它看起來像是經典的生產者/消費者模式,但是在兩個層面上,我沒有做到這一點。

長話短說:不要越過溪流! (哈哈)

NSStream是基於RunLoop的抽象(也就是說,它打算在NSRunLoop上協同工作, NSRunLoop是GCD之前的一種方法)。 如果您主要在其余代碼中使用GCD支持並發,那么NSStream並不是進行I / O的理想選擇。 GCD提供了自己的用於管理I / O的API。 請參閱本頁上標題為“管理調度I / O”的部分。

如果要繼續使用NSStream ,可以通過在主線程RunLoop上調度NSStream進行,也可以啟動專用的后台線程,在那兒的RunLoop上調度它,然后在該線程和您的GCD隊列。 (...但不要那樣做;只需硬着頭皮並使用dispatch_io 。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM