1

クライアントが送信したものをエコーバックするマルチスレッドサーバーアプリケーションを作成しています。新しいクライアントごとに 1 つのスレッドを生成しています。ループを使用して、while(1)連続するクライアントを無期限に処理しました (正確には無期限ではありません。強制的に 64 に制限し、その後は新しい接続を拒否しました)。ここで、サーバー アプリケーションで Ctrl+C シグナルを処理する必要があります。

1 つの問題は、マルチスレッド アプリケーションでの使用が推奨されないことです。signal()

ただし、 SO で既に説明しSIGINTた方法を使用して (Ctrl+C から) シグナルをキャッチするために使用したとしても、これを行う必要があります 。1) サーバーはこれ以上クライアントを受け入れません。 2) クライアントが切断を選択した場合を除き、サーバーへの現在の接続は継続する必要があります。

私のシグナルハンドラ関数は次のとおりです。

void Ctrl_C_handler(int sig)
{
    if(sig == SIGINT)       // Ctrl+C
    {
        printf("Ctrl+C detected by server !!\n");
        printf("No more connections will be accepted!!");
        pthread_cancel(main_thread_id);
    }
}

スレッドをキャンセルするために main() 内で使用することを提案するメソッドは次のとおりです。

// Method 1
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

            // ..
            // client handling
            // ..
}

// Method 2

while(1)
{   
    pthread_testcancel();       // Create Cancellation point
            // ..
            // client handling
            // ..
}

// Method 3

while(1)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
            // ..
            // client handling
            // ..
}

私が使用している理由pthread_cancel()

このリンクによると、スレッドはpthread_exit()(要件 1 が満たされている) を使用して最終的に終了します。のNOTES セクションでpthread_exit()は、他のスレッドが実行を継続できると説明しているため (要件 2 が満たされている)。

今ここまで正しければ、

スレッドのキャンセルに最適な方法はどれですか。
方法 3 を選択した理由は次のとおりです。

(デメリット) 方法 1: スレッドがメモリを割り当てる場合、非同期スレッドのキャンセルは安全ではありません (SO の回答で見たように)。その他の理由はほとんどありません。

(デメリット) 方法 2:このリンクによると、キャンセル ポイントとしても機能する関数が他にもたくさんあります。そのうちのいくつかをコードで使用します。

(メリット) 方法 3: 方法 2 に似ていますが、スレッドがキャンセル不可であるため、他のキャンセル ポイントがアクティブにならないため安全です。

私のやり方が正しいか教えてください。pthread_cancel() を使用する以外に、Ctrl+C を同様に処理するためのより良い方法はありますか?

4

1 に答える 1

2

キャンセルは避けたほうがいいと思います。

代わりに、サーバーのリッスン ソケットを close() する SIGINT ハンドラを登録します。(これにはsigactionを使用します。) ソケットが閉じられた後、メイン スレッドは正常に終了し、クライアント スレッドは実行されたままになります。

たとえば、擬似コードで:

static int listen_fd = -1               // server socket

void handle_SIGINT(int s):              // Requirement 1
  if listen_fd >= 0:
    close(listen_fd)
    listen_fd = -1

int main(...):
  listen_fd = new_listening_socket(...)
  block_signal(SIGINT)
  trap_signal(SIGINT, handle_SIGINT)    // again, calls sigaction

  while 1:
    unblock_signal(SIGINT)
    new_client = accept(listen_fd)
    block_signal(SIGINT)

    if new_client < 0:                  // Requirement 1, also general error handling
      break

    spawn_worker_thread(new_client)     // probably attr PTHREAD_CREATE_DETACHED

  pthread_exit(NULL)                    // Requirement 2
  return 0                              // not reached

もちろん、必要に応じて、より微妙なエラー処理、クリーンアップ ルーチンなどを含めることができます。

于 2013-08-21T14:36:18.477 に答える