12

POSIX Threadsを利用するマルチスレッド アプリケーションを開発しています。私は定期的なジョブを実行するためにスレッドを使用しており、その目的のためにusleep(3)を使用してスレッドの実行を一時停止しています。私の質問は、メイン スレッドから usleep() タイマーをキャンセルする方法です。試してみpthread_kill(thread, SIGALRM)ましたが、グローバルな影響があり、メイン アプリケーションが終了します (デフォルトで)。ここに私の疑似コードがあります:

void threaded_task(void *ptr) {
    initialize();

    while(running) {
        do_the_work();
        usleep(some_interval);
    }

    clean_up();
    release_resources();
}

そして、メイン スレッドから指定されたスレッドを停止 (および正常にシャットダウン)するために使用される疑似関数を次に示します。

void stop_thread(pthread_t thread) {
    set_running_state(thread, 0); // Actually I use mutex staff
    // TODO: Cancel sleep timer so that I will not wait for nothing.
    // Wait for task to finish possibly running work and clean up 
    pthread_join(thread, NULL);
}

私の目標を達成するための便利な方法は何ですか? 条件変数を使用する必要がありますか、それとも sleep() バリアントを使用してこれを行うことができますか?

4

8 に答える 8

9

ウェイクselect()アップするために突くことができる FIFO またはソケットで使用します。

于 2010-10-25T16:36:36.953 に答える
6

セマフォを使用してスリープすることもできます (実際、それがセマフォの本当の目的です)。

asema_waitをスレッドに、 asema_postをメインスレッドに。簡単で、きれいで、持ち運び可能です。手順を詳述した記事へのリンク: http://www.netrino.com/node/202

于 2010-10-25T18:13:55.327 に答える
5

SIGALRM がアプリケーション全体を強制終了している理由は、おそらくシグナル ハンドラーを登録していないためです。SIGALRM のデフォルトのアクションは、カーネルがプロセスを終了することです。そのため、usleepSIGALRM を使用しない方法で実装されている場合 (nanosleepたとえば、タイムアウトのあるポーリング関数のいずれかを使用する) usleep、ハンドラーまたはその他の方法で登録されていません。シグナルのデフォルトの配置を変更しました。

void handle_alrm(int sig) {
}

...

int main(void) {
    signal(SIGALRM, handle_alrm);
    ...

プログラムを強制終了しないようにするのに十分なはずですが、より複雑なsigaction関数を調べる必要がありますsignal。これは、より多くの制御が可能になり、異なるプラットフォーム間でより一貫して動作するためです。

usleepこれは、 SIGALRM を使用してorを実装するシステムでコードを使用しようとすると問題を引き起こす可能性があるsleepため、それらの標準ライブラリ バージョンを使用せず、すべてのプラットフォームでより予測可能な実装を持つ関数を使用することをお勧めします。 (おそらく、nanosleep必要なインターフェイスを提供する薄いラッパーです)。

于 2010-10-25T17:50:39.793 に答える
4

pthread_cond_timedwait を使用して、タイムアウト付きの条件変数で待機を使用します

シャットダウンしたいときは、「shuting down」変数を設定し、pthread_cond_broadcast を実行します。

于 2010-10-25T17:49:52.830 に答える
2

たぶん、シグナルマスクをいじる必要があるか、シグナルがusleepから抜け出せないかもしれません...わかりません。sigwait() または sigtimedwait() を使用できるかどうかはわかりません。pthread_kill を使用してスレッドをウェイクしますが、sigwait を使用してスレッドをスリープさせます....usleep ではありません。これは、これを実行するために私が見つけた最速の方法です (私のテストによると、pthread_cond で待機するよりも 40 倍から 50 倍高速です)。

スレッドを作成する前にこれを行います。

int fSigSet;
sigemptyset(&fSigSet);
sigaddset(&fSigSet, SIGUSR1);
sigaddset(&fSigSet, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &fSigSet, NULL);

作成されたすべてのスレッドは、このマスクを継承します。マスクにちょっと戸惑う。特定のシグナルに対して何もしないようにシステムに指示しているか、いくつかのシグナルを処理していることをシステムに伝えている可能性があります...わかりません。他の誰かが参加して、私たちを助けてくれます。マスクがどのように機能するかをもっとよく知っていれば、上記のコードを ThreadProc に貼り付けることができると言えるかもしれません。また、SIGSEGV が必要かどうかもわかりません。

次に、スレッドはこれを呼び出して自分自身をスリープさせます。

int fSigReceived;
// next line sleeps the thread
sigwait(&fSigSet, &fSigReceived);  // assuming you saved fSigSet from above...
// you get here when the thread is woken up by the signal
// you can check fSigReceived if you care what signal you got.

次に、これを実行してスレッドを起動します。

thread_kill(pThread, SIGUSR1);
于 2011-01-13T01:56:32.850 に答える
2

の代わりに、pthread 条件変数 ( 、、およびを参照)、SysV セマフォ、または POSIX セマフォselectを使用することもできます。これらはすべて、イベント処理スレッドの usleep よりも適しています。pthread_cond_initpthread_cond_waitpthread_cond_signal

于 2010-10-25T16:44:00.283 に答える
2

参照されている man ページから、Linux で実行しているようです。nanosleep を使用して子プロセスにアプリケーションを割り込ませる (SIGRTMIN+x) ことができるはずです。Nanosleep には、信号によって中断され、スリープしていたはずの残り時間を返す機能があります。睡眠に長い時間を使用している場合は、睡眠を使用することもできます。

ナノスリープ(2)

シグナル(7)

上記の任意の種類の IPC も、この問題の解決に役立ちます。

編集:プログラムに外部影響を与えない信号を使用する必要があることを除いて、すでにこれを行っているようです。スリープ機能のいずれも、ブロックされていない信号によって中断される必要があります。リアルタイム信号は、アプリケーションごとに使用することを意図しています。

于 2010-10-25T16:49:29.420 に答える
2

これを行うにはいくつかの方法があります。

  • @Ignacio が言及しているセルフパイプ トリックを使用します (Linux はeventfd(2)パイプを置き換えるために便利ですが、移植性はありません) 。
  • ミューテックスと条件変数を中心に構築されたブロッキング キューを介してスレッドを接続し、空のキューで待機し、キュー内のアイテムでウェイクアップします
  • 他のスレッドを開始する前にメインスレッドでシグナルをブロックし、シグナルを待機し、シグナルでウェイクします-参照pthread_sigmask(3)
于 2010-10-25T17:05:20.053 に答える