1

Objective-C でシリアル通信ラッパー クラスを作成しています。使用可能なすべてのシリアル モデムを一覧表示し、接続をセットアップするために、Apple によるこのサンプル プロジェクトで使用されているものとほとんど同じコードを使用しています。

アップルのやり方を読んだり書いたりすることができました。しかし、私は 2 番目のスレッドにループを実装し、NSString *writeStringより長い 0 の場合はストリームに書き込み、バイトが利用可能な場合は書き込み後に読み取りたいと考えています。

私は非常に簡単に書くことができました。writeで宣言されている関数を使用しましたunistd.h

読み取りは機能しません。を呼び出すたびにread()、関数がハングし、ループが進行しません。

私のループで使用されるコードは次のとおりです。

- (void)runInCOMLoop {
    do {
        // write
    } while (bytesWritten < strlen([_writeString UTF8String]));

    NSMutableString *readString = [NSMutableString string];
    ssize_t bytesRead = 0;
    ssize_t readB = 0;
    char buffer[256];

    do {
        readB = read(_fileDescriptor, &buffer, sizeof(buffer));
//              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this function hangs
        bytesRead += readB;

        if (readB == -1 {
            // error
        }
        else if (readB > 0) {
            if(buffer[bytesRead - 1] == '\r' ]] buffer[bytesRead - 1] == '\n') {
                break;
            }

            [readString appendString:[NSString stringWithUTF8String:buffer]];
        }
    } while (readB > 0);

ここで何が間違っていますか?

4

2 に答える 2

1

read() は、読み取るものが何もない場合にブロックされます。Apple にはおそらく独自の機能がありますが、select() を使用して、読むべきものがあるかどうかを確認できます_fileDescriptor。select の使用方法の例については、Google で検索してください。

StackOverflow に関する 1 つのリンクを次に示します。

fdが「準備完了」になることをselect()がどのように警告するかの例を教えてください

select man からのこの抜粋は次のとおりです。

     To effect a poll, the timeout argument should be
     non-nil, pointing to a zero-valued timeval structure.  Timeout is not
     changed by select(), and may be reused on subsequent calls, however it is
     good style to re-initialize it before each invocation of select().
于 2013-11-14T16:17:10.220 に答える
0

データを待たないようにするためO_NONBLOCKにファイル記述子に非ブロック フラグ ( ) を設定できますが、そうすると、データを探して継続的にポーリングする必要があり、これは CPU 使用率の観点から明らかに悪いことです。チャーリー・バーンズの答えが説明しているように、最良の解決策は、ポートのファイル記述子で読み取られるデータがあるまでプログラムが効率的に待機できるようにすることです。以下は、私自身の Objective-C シリアル ポート クラスであるORSSerialPort (わずかに変更されています)から取得したサンプル コードです。fcntl()read()select()

fd_set localReadFDSet;
FD_ZERO(&localReadFDSet);
FD_SET(self.fileDescriptor, &localReadFDSet);

timeout.tv_sec = 0; 
timeout.tv_usec = 100000; // Check to see if port closed every 100ms

result = select(localPortFD+1, &localReadFDSet, NULL, NULL, &timeout);
if (!self.isOpen) break; // Port closed while select call was waiting
if (result < 0) {
    // Handle error
}

if (result == 0 || !FD_ISSET(localPortFD, &localReadFDSet)) continue;

// Data is available
char buf[1024];
long lengthRead = read(localPortFD, buf, sizeof(buf));
NSData *readData = nil;
if (lengthRead>0) readData = [NSData dataWithBytes:buf length:lengthRead];

select()はデータが返されることを示していることに注意してください。select()そのため、データが利用できない間、プログラムは呼び出し時に中断されたままになります。プログラムはハングしていません。それが動作するはずです。select()が待機している間に他のことをする必要がある場合は、select()実行する必要がある他の作業とは別のキュー/スレッドに呼び出しを配置する必要があります。ORSSerialPortこれを行います。

于 2013-11-15T19:50:03.923 に答える