6

次のような状況があります。

fread 呼び出しでデバイスから読み取るスレッドがあります。デバイスからデータが送信されない限り、この呼び出しはブロックされます。このスレッドを停止すると、このスレッド内にぶら下がったままになります。

今、freadのmanページ内で次のことを見つけました:

エラー

単一 UNIX 仕様に準拠するすべてのシステムで、fread() 関数は、次の条件にリストされているように errno を設定します。

[EINTR] シグナルの受信により読み取り操作が終了し、データは転送されませんでした。

これは、別のスレッドからの呼び出しを中断する方法があることを意味します。しかし、方法がわかりません。fread コールを中断する信号を送信する方法を教えてもらえますか? そして、私が送信する必要がある信号は何ですか?


更新 08-10-10 09:25

私はまだそれを機能させていません。kill() と pthread_kill() を異なるシグナルで試しました。しかし、 fread() 呼び出しを中断するものはないようです。私が機能した唯一のことは、アプリケーション全体を強制終了することですが、それは私が望んでいることではありません。

4

6 に答える 6

10

1. シグナル:

他の多くの人が指摘したように、シグナルを使用するとうまくいきます。ただし、他の多くの人も指摘しているように、このアプローチには欠点があります。

2.Select():

select() (またはその他の多重化関数) を使用すると、複数のファイル記述子からデータが到着するのを待つのをブロックし、タイムアウトを指定できます。

タイムアウトを有利に使用してください。select() が戻るたびに、グローバル変数をチェックして、終了する必要があるかどうかを確認してください。すぐに反応したい場合は、読み続けてください。

3. Select() とパイプ:

複数の fds は、言及したデバイスや、たとえばパイプを介してデータが到着するのを待つことができることを意味します。

スレッドを作成する前に、パイプを作成してから、デバイスとパイプの両方を監視する select() でスレッド ブロックを設定します。デバイスに新しいデータがあるかどうかを選択してブロックを解除したいときはいつでも、パイプにバイトを送信します。

select() が、パイプを介してデータが到着したためにブロックが解除されたことを通知した場合は、クリーンアップして終了できます。この方法は、パイプをウェイクアップ方法として使用するだけでなく、有用な情報やコマンドを渡すために使用できるため、シグナリング方法よりもはるかに柔軟であることに注意してください。

4. Select()、パイプ、シグナル:

複数のプロセスを使用していて、パイプを通過したくない/通過できない場合は、両方のソリューションを組み合わせることができます。パイプを作成し、SIGUSR1 などのシグナル ハンドラをインストールします。シグナル ハンドラーで、パイプを介して 1 バイトを送信します。

プロセスが SIGUSR1 を送信するたびに、ハンドラーが呼び出され、select() のブロックが解除されます。fdsets を調べると、それが自分自身のプログラムが自分自身にシグナルを送る以外の理由ではないことがわかります。

于 2010-10-07T20:25:12.667 に答える
4

select(2)まったくブロックせずに、またはそのデバイスのみをブロックせずに、そのファイル記述子で利用可能なデータがあるかどうかを確認できるシステムコールについて本当に読みたいと思います。

于 2010-10-07T14:07:14.723 に答える
3

をご覧くださいman 2 kill。(またはこちらをご覧ください

しかし、あなたはこれをしたくないと感じています--ほとんどの場合、人々は errnoEINTRを無視して読み直します。代わりに、ノンブロッキング読み取りを検討することをお勧めします。

于 2010-10-07T14:03:24.797 に答える
2

スレッドでは、 でブロックする代わりにfread、 でブロックしselectます。戻ったらselect、「am I done」変数をチェックします。完了していない場合は、呼び出しfreadてデータを取得できます。

freadスレッドを停止したい他のスレッドから、「am I done」変数を設定してからfdを閉じて、freadスレッドがselectすぐに起動するようにします。

コンテキストによって fd を閉じることができない場合 (デバイスから読み取っていると言いますが、開いたままにしたいソケットがあったとします)、他のスレッドから書き込む 2 番目の fd を開いて wake up することができますselect

以下のコメントで示唆されているように、fd を閉じてウェイクアップselectすることは移植性がない場合があります。上記の second-fd 戦略を使用して、これをより移植性の高い方法で実現できます。

于 2010-10-07T15:53:36.903 に答える
0

kill()システムコールを使用できます。

アップデート

私はあなたの質問を読み違えていることがわかりました。R.が以下で指摘したように、kill()スレッドではなくプロセスを強制終了するためだけです。

于 2010-10-07T14:04:34.163 に答える
0

シグナルハンドラーは、割り込みfreadとしてインストールされていない限り割り込みません。未処理のシグナルは決して割り込みません。POSIX 標準では、signal関数によってインストールされたハンドラーをデフォルトでウィザー割り込みまたは非割り込みにすることが許可されているため (Linux ではデフォルトで非割り込み)、特定の動作が必要な場合は、sigaction関数を使用して目的の を指定しますsa_flags。特に、SA_RESTARTフラグを省略する必要があります。例えば:

struct sigaction sa = { .sa_handler = dummy_func, .sa_flags = 0 };
sigaction(SIGUSR1, &sa, 0);

sa_flags省略された場合はとにかく暗黙的に 0 になることに注意してください。ただし、説明のために初期化子に明示的に含めました。次に、またはfreadを送信SIGUSR1してを中断できます。killpthread_kill

于 2011-06-04T16:35:22.160 に答える