ブロッキングI/OとノンブロッキングI/Oについて

このQ&Aのポイント
  • I/O処理をブロックする必要性とは何か
  • ブロッキングI/OとノンブロッキングI/Oの使い分け方法
  • なぜ初期状態ではブロッキングI/Oが適用されるのか
回答を見る
  • ベストアンサー

ブロッキングI/Oについて

シリアルポートとGPIOポートを両方使用したプログラムを作成しました。read関数を使用した部分でブロッキングI/Oが原因となりGPIOポートが利用できなくなるという問題が起きました。 この問題自体はノンブロッキングI/Oの設定を行うことで解決できたのですが、以下の疑問が残りました。 ・なぜI/O処理をブロックする必要があるのか ・ブロッキングI/OとノンブロッキングI/Oはどのように使い分けるのか ・ブロッキングI/Oという機能は何故出来たのか I/Oポートの制限を行わない方がプログラムを作成しやすいと思うのですが、なぜread関数などは初期状態がブロッキングする状態になっているのでしょう。

  • MIRS
  • お礼率42% (3/7)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

>・なぜI/O処理をブロックする必要があるのか 「ノンブロッキング」はデータの受信(送信)完了を待たずに次の処理に移行することができる。 逆にいえば、受信データがそろわないうちに処理を行う為、データ欠損による問題が発生する場合があります。 もしくは、処理途中で次のデータを受信しバッファの上書きの可能性もあります。 >・ブロッキングI/OとノンブロッキングI/Oはどのように使い分けるのか H/W特性、データ内容、それに付随する処理内容によって決定する。 >・ブロッキングI/Oという機能は何故出来たのか 前述の通り。 「なぜ」というよりも「なければ困る」から。 >I/Oポートの制限を行わない方がプログラムを作成しやすいと思うのですが、 「プログラムを作成しやすい」というのは間違いです。 それは「H/W特性」を理解せずにプログラムを作成していることに他なりません。 read「関数」はあくまでも「データを入力する」という抽象的な機能しか持っていません。 その先(入力I/F)が何かは理解できません。これを理解し適切に処理するのがプログラマーの役割です。 >なぜread関数などは初期状態がブロッキングする状態になっているのでしょう。 データを受信して処理を行っている間は、後発データによる上書きを禁止するため。

MIRS
質問者

お礼

ノンブロッキングにした場合データが受信途中のまま次の処理に移行してしまうということになるんですね。 H/W特性やデータ内容を考えた時にはブロッキングの方が良くなることもあるということを考えながらこれからプログラムを作っていきたいと思います。 ありがとうございました。

関連するQ&A

  • read関数をノンブロッキングで実行する(c言語)

    read関数をノンブロッキングで実行する方法がわかりません。 O_NONBLOCKを使用して、readがEAGAINを返したらどうのこうのと、マニュアルにありましたが その辺の一連をどのように書けばよいのかを教えてください。 unix上でTCPでやりたいです。

  • I/Oポートorシリアルインタフェースがたくさんあるマイコン

    I/Oポートorシリアルインタフェースがたくさんあるマイコン 現在、I/Oポート若しくはシリアルインタフェースがたくさんあるマイコンを探しています。 10系統のコマンドを1個のマイコンで受け、その統計を取るような制御をしたいのですが、系統が多いため、なかなかデバイスが見つかりません。 コマンドは16ビット+ストローブ1ビットの計17ビットを予定しており、これが10系統なので170個のI/Oポートが必要になります。 コマンドそのものはシリアルで通信する事も可能ですが、10系統のシリアルを持つデバイスもなかなか無いので困っています。 170個以上のI/Oポートを持っているor10系統以上のシリアルインタフェースを制御できるマイコンを紹介頂けないでしょうか?

  • シリアル通信でのread関数の戻り値

    オムロン製PLCと上位コンピュータをRS232Cで接続し、FINSコマンドを用いてシリアル通信をしようとしています。 現在作っているプログラムの流れは、 ・シリアルポート"/dev/ttyS2"のオープン   comm_fd = open("/dev/ttyS2", O_RDWR | O_NOCTTY); ・通信設定   termios構造体を設定 ・コマンドフレーム(COMMAND)を作成し、ポートに書き込む   write(comm_fd, &COMMAND, strlen(COMMAND)); ・PLCからのレスポンスを読み出す   read(comm_fd, &RESPONSE, 256); のようにしているのですが、read関数が実行されたままになってしまいます。(エラーコードも返ってこない状態です) readの戻り値が-1ならポートにアクセスできていないとわかるのですが… ためしにcomm_fdと違う値をread関数に入れてみたところ(read(6, &RESPONSE, 256)、戻り値は-1となりました。 これはどういう状態になってしまっているのでしょうか? わかりにくい質問で申し訳ありません。

  • 非ブロッキングソケットのrecvについて

    現在、Winsock2を使ってあるサーバーのプログラムを作成しています。 WSAEventSelect関数を使って非ブロッキングソケットを扱っているのですが、複数のクライアントからほぼ同時に接続要求などがあった際に 接続を取りこぼしてしまいます。 どなたかアドバイスいただけませんでしょうか。 以下、ソースを示します。プログラムの動作をわかりやすくするためエラー処理などは省略して記載します。(実際には行っています) ちなみに非ブロッキングソケットを使用する理由は以下のとおりです。 ・GUIアプリのワーカースレッドで動作させており、ブロッキングソケットでブロック中にメインスレッドが終了してもワーカースレッドがそれを知る術がなくワーカースレッドを安全に終了させることができないため。 /* 変数の宣言*/ int iRet=-1; SOCKET ListenSock; SOCKET AcceptSock; int iRcvClientLen=0; int iRcvLen=0; char caRcvDat[1024]={0}; WSAEVENT hEvent; DWORD dwResult; WSANETWORKEVENTS events; /* リッスンソケットを作成*/ ListenSock = socket(AF_INET, SOCK_STREAM, 0); /* イベントのクリエイト*/ hEvent = WSACreateEvent(); /* リッスンソケットの設定*/ addr.sin_family = AF_INET; addr.sin_port = htons(PORT_NUM); /*PORT_NUMは定数*/ addr.sin_addr.S_un.S_addr = INADDR_ANY; /* リッスンソケットをバインド*/ iRet = bind(ListenSock, (struct sockaddr *)&addr, sizeof(addr)); /* リッスンソケットでポートを開く*/ iRet = listen(ListenSock, 10); /* クライアント接続待ちの無限ループ*/ while (1) { printf("\n\n/--------- 待機中 ---------/\n\n"); iRcvClientLen = sizeof(client); /* リッスンソケットにACCEPTイベントを設定*/ iRet = WSAEventSelect(ListenSock, hEvent, FD_ACCEPT); /* ACCEPTイベント発生まで待機*/ dwResult = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE); /* 発生したイベントを解析*/ iRet = WSAEnumNetworkEvents(ListenSock, hEvent, &events); /* イベント変数をリセット*/ WSAResetEvent(hEvent); /* 発生したイベントがACCEPTであれば接続を受け入れる*/ if(events.lNetworkEvents & FD_ACCEPT){ AcceptSock = accept(ListenSock, (struct sockaddr *)&client, &iRcvClientLen); } /* ACCEPTしたソケットにREADイベントを設定しなおす*/ iRet = WSAEventSelect(AcceptSock, hEvent, FD_READ); /* READイベント発生まで待機*/ dwResult = WSAWaitForMultipleEvents(1, &hEvent, FALSE, WSA_INFINITE, FALSE); /* 発生したイベントを解析*/ iRet = WSAEnumNetworkEvents(AcceptSock, hEvent, &events); /* イベント変数をリセット*/ WSAResetEvent(hEvent); /* 発生したイベントがREADであればデータを読み込む*/ if(events.lNetworkEvents & FD_READ){ iRcvLen=recv(AcceptSock, caRcvDat, 1024, 0); /* ・・・以下Recv後の動作・・・*/ } } おそらく、2回目のWSAWaitForMultipleEvents関数で待機している間に接続要求が来たクライアントを取りこぼしているのだと思いますが、 対処方法がわかりません。

  • I/Oボードについて

    現在、研究でi/oボード及びAD/DAボードを用いて電源の電流値を制御いようとしています。(使用している言語はC++) しかし、この研究の前任者とお会いしたことがなく、引き継ぎ作業が不十分で、これまで制御に携わったことがない私にとって取説等を呼んでも何が何だかさっぱりわかりません。 そこで、以下のことを質問させて頂きます。 ・I/Oボードは、端的に述べるとどういう役割を担っているのでしょうか?ちなみに、私が使うボードは1chタイプのシリアルI/Oボードです。 ・アナログ入力とアナログ出力の違いがよくわかりません。どちらがDAでどちらがADの信号でしょうか? ・関連事項でわかりやすい図書やサイト等がございますでしょうか? 初歩すぎる質問で大変申し訳ありませんが、わかる範囲でかまいませんので、ご回答よろしくお願いします。

  • I/Oボードについて

    在、研究でi/oボード及びAD/DAボードを用いて電源の電流値を制御いようとしています。(使用している言語はC++) しかし、この研究の前任者とお会いしたことがなく、引き継ぎ作業が不十分で、これまで制御に携わったことがない私にとって取説等を呼んでも何が何だかさっぱりわかりません。 そこで、以下のことを質問させて頂きます。 ・I/Oボードは、端的に述べるとどういう役割を担っているのでしょうか?ちなみに、私が使うボードは1chタイプのシリアルI/Oボードです。 ・アナログ入力とアナログ出力の違いがよくわかりません。どちらがDAでどちらがADの信号でしょうか? ・関連事項でわかりやすい図書やサイト等がございますでしょうか? 初歩すぎる質問で大変申し訳ありませんが、わかる範囲でかまいませんので、ご回答よろしくお願いします。

  • I2C I/OエクスパンダPCA9539動作不具合

    ちょっと細かい質問になりますが、ICの不具合かどうか最終判断を下そうと 思っておりまして、その前にこのサイトで別の角度からアドバイスを受けられたら と思い投稿させて頂きました。 本来、製造メーカに聞くべき問題かもしれませんがよろしくお願い致します。 PIC16F887でI2Cバスを経由しI/OエクスパンダPCA9539(以降9539)を制御しています。 9539については http://www.jp.nxp.com/products/interface_and_connectivity/i2c/i2c_general_purpose_i_o/series/PCA9539_PCA9539R.html をご参照ください。 9539の動作のうち、ポートの出力はうまくいっていますが、ポートへの入力を読みだそうとするとおかしな動作をしています。SCL,SDAの駆動波形自体をみて期待と異なる動作をしているように見えます。なお、PICのコードはCCS社Cコンパイラの専用組み込み関数を用いています。 添付画像をご参照ください。 まず、最初の2バイトで9539への読みだしコマンドの書き込みを行っています。書き込んだコマンドはポート0からの入力を意味する"0x00"です。ここまでは後続の3バイト(下に時間域を拡大)で問題が起きており、R="1"と矢印で示したbitでREADを意味する1を立てていますが、その直後9539からACKが返っていません(ACK=highになっている)。当然、その後に読みだされた2つの"FF"も実際の状態とは異なっています。 ちなみに、このICはNXP社の物ですが、同じコードをTI社の同じ型番のコンパチ品で試すとこのACKは返しますが、読みだす値は常に"FF"になってしまいます。 【質問】  ・上記の読みだし動作で駆動の仕方を間違えておりますでしょうか?  ・同様のおかしな振る舞いをご経験された方いらっしゃいますか?

  • PIC 18F2320のI/Oポート

    PIC 18F2320のI/OポートにおいてポートCの5ビット目の出力が ビットセットしてもLowのままでHighになりません。 ポートCはすべて出力設定になっているし、SPIも使用していません。 ちなみにポートCの5ビット目以外は、ビットセットでHighに変化します。 ハードの接続(回路)の問題はないと思います。 何か他に設定すべきところがあれば教えてください。

  • I/Oレジスタアドレスを関数に引数として渡すには?

    C言語について質問があるので投稿させていただきました。 現在Renesas製 RXマイコンにてポート制御のプログラムを作成しています。 そこで一点分らない点がありましたのでご教授いただければ幸いです。 現在I/Oポートレジスタの入出力設定を行っています。 レジスタ値を書き換えるだけであれば下記の通りかと思います。 #define PORTA (*(volatile unsigned char *)0x0008C00A) PORTA = 0x01; レジスタアドレスを引数として関数に渡し関数内でレジスタ値を書き換えるにはどうすれば よろしいでしょうか。 void main(void) { setPinMode(PORTA); PORTA.PODR.BIT.B0 = 0x01; while(1); } void setPinMode(uint32_t* portNumber) { *portNumber = 0x01; } としていますが上手くいきません。 型がおかしい? ポインタってものが分かってない? など色々考えてはみたのですが何分初心者なので解決に至っておりません。 よろしければご教授の程よろしくお願いいたします。

  • I/Oデバイス って何?

    自作パソコンを使用していますが、カードリーダーでSDカードを読み込もうとしたら、I/Oデバイスエラーが出てきちゃいました。他のメモリースティックやスマートメディアは問題なく使用できます。解決方法を教えてください。

専門家に質問してみよう