タイマーを使用して一定のサンプルレート (200Hz) でデータの取得と処理を行うアプリケーションを作成しています。アプリケーションはサーバーのように機能し、バックグラウンドで実行されます。UDP から他のプロセスまたは他のマシンから制御できる必要があります。
そのために、timer_create() API を使用して定期的に SIGUSR1 を生成し、取得と処理を行うハンドラーを呼び出します。
タイマーを構成するコードは次のとおりです (明確にするためにエラー チェックを差し引いています)。
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_ptr = &timerid;
timer_create(CLOCK_REALTIME, &sev, &timerid);
timer_settime(...)
上記のコードは、UDP から「開始」コマンドを受信したときに呼び出されます。コマンドを確認するために、メイン プログラムに recvfrom() syscall を呼び出す無限ループがあります。
問題は、「開始」コマンドが受信され、タイマーが適切に開始されて実行されている場合 (上記のコードを使用)、タイマーによって送信された SIGUSR1 シグナルが原因で「中断されたシステム コール」エラー (EINTR) が発生することです。 recvfrom() 呼び出しを中断します。この特定のエラー コードをチェックして無視すると、最終的に recvfrom() を呼び出すときに「接続が拒否されました」というエラーが発生します。
だからここに私の質問:
- この 'interrupted system calls' エラーを解決するにはどうすればよいですか?
- 約 20 回試行した後に「接続が拒否されました」というエラーが表示されるのはなぜですか?
- 私が理解しているように、SIGEV_THREADを使用すると解決策になる可能性があると感じています。シグナルを生成せずに新しいスレッド(phread_createなど)を作成します。私は正しいですか?
- ここでシグナル番号は重要ですか?リアルタイム信号を使用するプラスはありますか?
- 私が意図していることを行う他の方法はありますか: UDP からのコマンドとリアルタイムの定期的なタスクをバックグラウンド ループでチェックすることはありますか?
そしてここにボーナスの質問があります:
- ハンドラーでデータの取得と処理を行うのは安全ですか?それとも、セマフォ メカニズムを使用してそれを行うスレッドを起動する必要がありますか?
解決策: 回答とコメントで提案されているように、SA_RESTART を使用すると主な問題が解決するようです。
解決策 2: SIGEV_SIGNAL よりも SIGEV_THREAD を使用しても機能します。SIGEV_THREAD を使用すると、SIGEV_SIGNAL よりも多くのリソースが必要になる可能性があることをどこかで読んだことがあります。ただし、タスクのタイミングに関して大きな違いは見られませんでした。