2016-02-22 16 views
12

私はこのように見えるコードをいくつか持っています。このコードの一部が接続を待っている間に無限ループで実行されるため、プログラムを終了すると、そこからのみ終了します。決して実行しないコードを処理する方法

main(){ 

// do some stuff.... 

    while(1) { 
     int newFD = 
      accept(sockFD, (struct sockaddr *)&client_addr, &client_addr_size); 
     if(newFD == -1) { 
      std::cerr << "Error while Accepting on socket" << std::endl; 
      continue; 
     } 

     if(!fork()) { 

      close(sockFD); // close child's sockfd - not needed here 

      // lalala do stuff send message here     

      close(newFD); // finally close its newFD - message sent, no use 
      return 0; 
     } 
     close(newFD); // close parent's newFD - no use here 
    } 

    // now execution never reaches here 
    close(sockFD);  // so how to handle this? 
    freeaddrinfo(res); // and this? 

    return 0; 
} 
+0

私はそれをそのまま残し、OSはそれを世話するべきだと思いますか? – buggy3

+5

このケースでは、私は終了信号をフックし、それを使ってプログラムをきれいに終了させたいと思います。一般的には、決して実行されないコードに対しては削除してください。バージョン管理で古いデッドコードを追跡できるようにします。 – Niall

+1

ソケットのクローズを処理する方法、またはコード自体をどうすればいいですか? – rhughes

答えて

15

することができますし、あなたのコードは、他の人が使用するか、あなた自身がちょうどそれがクリーナーたい場合は、おそらく終了ハンドラを追加する必要があります。出口ハンドラでは、ループを終了させるフラグを切り替えることができます。while()次のコードは、このユースケースで100%正常に動作し、信頼できるクロスプラットフォームですが、より複雑なものを実行するには、適切なスレッドセーフなOS固有の関数またはBoostやC++などのものを使用する必要があります11

最初に2つのグローバル変数を宣言し、それらをvolatileにして、コンパイラが常に実際にメモリ値を読み書きするようにします。 volatile宣言しなければ、コンパイラはその値をレジスタに入れて、これを動作させない可能性があります。揮発性の設定では、すべてのループ上のメモリ位置を読み込み、複数のスレッドがあっても正しく動作します。

volatile bool bRunning=true; 
volatile bool bFinished=false; 

し、代わりにあなたのwhile(1) {}ループの、自分の終了ハンドラでこの

while(bRunning) 
{ 
    dostuff 
} 
bFinished=true; 

に変更し、単にあなたは、オペレーティング・システムを指定していないが、それは見えますbRunning=false;

void ExitHandler() 
{ 
    bRunning=false; 
    while(bFinished==false) { Sleep(1); } 
} 

を設定あなたがLinuxベースであるように、あなたはこれを必要とするLinux上でハンドラを設定します。

void ExitHandler(int s) 
{ 
    bRunning=false; 
} 

int main() 
{ 
    struct sigaction sigIntHandler; 
    sigIntHandler.sa_handler = ExitHandler; 
    sigemptyset(&sigIntHandler.sa_mask); 
    sigIntHandler.sa_flags = 0; 
    sigaction(SIGINT, &sigIntHandler, NULL); 
    while(bRunning) 
    { 
     dostuff 
    } 
    ...error_handling... 
} 

コンソールアプリケーションの場合、Windowsでは次のようになります。

BOOL WINAPI ConsoleHandler(DWORD CEvent) 
{ 
    switch (CEvent) 
    { 
     case CTRL_C_EVENT: 
     case CTRL_BREAK_EVENT: 
     case CTRL_CLOSE_EVENT: 
     case CTRL_LOGOFF_EVENT: 
     case CTRL_SHUTDOWN_EVENT: 
      bRunning = false; 
      while (bFinished == false) Sleep(1); 
      break; 
    } 
    return TRUE; 
} 

int main() 
{ 
    SetConsoleCtrlHandler(ConsoleHandler, TRUE); 
    while(bRunning() 
    { 
     dostuff 
    } 
    ...error_handling... 
} 

ここでbFinishedをテストして待機する必要があることに注意してください。 Windowsでこれをしないと、別のOS固有のスレッドによって終了ハンドラが呼び出されるため、アプリケーションのシャットダウンに時間がかかりません。 Linuxではこれは必要ではなく、メインスレッドのハンドラを終了して続行する必要があります。

注意すべきもう一つのことは、デフォルトでは、Windowsは終了するまでシャットダウンするのに約5秒しかかかりません。これは多くの場合残念です。多くの時間が必要な場合は、レジストリ設定(悪いアイデア)を変更するか、そのようなものに良いフックを持つサービスを実装する必要があります。あなたの単純なケースのためにそれはうまくいくでしょう。

+0

'fork()'?私はそうは思わない。 ;) –

+4

Hehe。私はちょうどWindowsコードを追加しました。これは、この同じ答えを検索するかもしれないが、代わりにWindows上にいる人にとっては関係があるからです。うまくいけば便利です! –

+4

'(PHANDLER_ROUTINE)ConsoleHandler'を実行しないでください。それは単に問題を求めているだけです。キャストは必要ありません。また、揮発性を使用し、最高のために望んでも良いではありません。むしろ、 'Interlocked *'関数群を使用してください。最後に、既存のスレッドのコンテキストでcontrol-Cハンドラが実行されていませんか?あなたがそのスレッドを終了するのを待っていたら、それは致命的になるでしょう... –

10

このような場合、OSはシャットダウン時にリソースを適切に解放して処理します。ただし、より一般的には、割り当てられたリソースが、プログラムによって実行されても自動的に再利用されても、リソースリークがプログラムの動作やパフォーマンスに影響を及ぼすため、確実に確保する必要があります。

現在のリソースに関しては、C++のすべてのリソースのようにそれらを扱わない理由はありません。受け入れられたルールは、それらをデストラクタで解放するオブジェクトにバインドすることです(RAIIイディオムも参照してください)。そうすれば、後で誰かがbreak文を追加したとしても、コードは正しく動作します。

ところで私がここで見るより深刻な問題は、適切なエラー処理の一般的な欠如です。

+3

あなたは 'エラー処理'の部分にコメントできますか?私は前にこの種の仕事をしたことがないので、あなたの提案に基づいてコードを改善したいと思います。 –

+1

簡単な例: 'fork()'マンページを見ると、それが返す3つの異なる値のグループがありますが、それらのうちの2つだけを区別します。 'fork()'が失敗した場合、私は 'std :: runtime_error(" fork()failed ")'をデフォルトのエラー処理のコンセプトとして投げ捨てるので、フォールトは気付かれません。これはここの他の関数にも当てはまります。ちょうどそれらの文書がどのようにエラーを通知するかを調べるためのドキュメントを読んでください。また、codereview.stackexchange.comでレビューのためにコードを投稿して、さらなる提案を得ることもできます。 –

+0

@UlrichEckhardtは良い点を示しています。できるだけエラー処理にRAIIをおすすめします。 C++ 17標準に移行する予定であるため、Rawソケット関数の代わりにASIOに目を通したいと思うかもしれません。また、あなたのアプリがクロスプラットフォームになることを可能にします。 WindowsソケットとLinuxソケットにはいくつかの違いがあり、移植が必要以上に困難になります。 –

関連する問題