2016-05-30 9 views
2

接続されたTCPソケットがノンブロッキングモードになっています。データの送受信は正しく機能します。などの専用スレッドにループとして実装されている受信:select()がタイムアウト時間を超えてブロックされることがある

fd_set fdset; 
FD_ZERO(&fdset); 
FD_SET(internal->m_socket, &fdset); 
struct timeval timeout; 
timeout.tv_sec = timeout_ms/1000; 
timeout.tv_usec = (timeout_ms % 1000) * 1000; 
int ret = select(internal->m_socket + 1, &fdset, nullptr, nullptr, &timeout); 
if (ret == 0) { 
    // handle timeout then loop 
} else if (ret < 0) { 
    // handle error then abort 
} else { 
    ret = recv(...); // Read data available on socket then loop 
} 

TCPコネクションは、OS X 10.11.5を実行している私のMacBookProからWiFi経由で行きます。接続が確立されている間にWiFiをオフにすると、フォローアップのあるselect()コールが指定したタイムアウト値よりかなり長くかかることがあります。ここで

は、ロギング呼び出しを追加することにより、証明をだ( INOUTを直前にそれぞれ印刷され、タイムアウト値に渡され、実際の測定された経過時間と select()後):

(WiFi is ON, thread is continuously receiving from socket) 

08:31:15 -------- IN = 15000 
08:31:30 -------- OUT = 14999 
08:31:30 -------- IN = 15000 
08:31:45 -------- OUT = 15000 
08:31:45 -------- IN = 15000 
08:32:00 -------- OUT = 15000 
08:32:00 -------- IN = 15000 
08:32:15 -------- OUT = 15002 
08:32:15 -------- IN = 1000 
08:32:15 -------- OUT = 87 <--- data received 
08:32:15 -------- IN = 4913 
08:32:15 -------- OUT = 0 <--- data received 
08:32:15 -------- IN = 15000 

(WiFi is turned OFF at this point in the middle of a `select()` call) 

08:32:30 -------- OUT = 15004 <--- ok 
08:32:30 -------- IN = 1000 
08:32:31 -------- OUT = 1003 <--- ok 
08:32:31 -------- IN = 1000 
08:32:32 -------- OUT = 1006 <--- ok 
08:32:32 -------- IN = 1000 
08:32:43 -------- OUT = 10999 <--- NOT OK: 10X longer 
08:32:43 -------- IN = 1000 
08:32:48 -------- OUT = 4965 <--- NOT OK: 5X longer 

(truncated) 

注意明白な存在しないことパターン:ときにはバグが起こっていないように見えることがありますが、ほとんどの場合そうです。指定したタイムアウトよりも長くかかったり、その後に1つ以上の時間がかかると、WiFiをオフにした後に即時にselect()コールを送信することができます。

+0

選択タイムアウトはわずか1秒ですか?どうして? – EJP

+0

このスニペットの上には多くのコードがあり、受信タイムアウトが発生すると他のロジックが実行されています。たとえば、私はデフォルトで15秒のタイムアウトを使用していますが、接続が機能していないとアプリが判断した場合、サーバーにPingを送信し、タイムアウトを1秒に減らし、Pongを数秒待ってから接続を終了します。受信していない。 – Pol

+1

これはApp Napです。問題が発生した時点で、アクティビティモニターの[エネルギー]タブにアプリが表示されているかどうかを確認します。 –

答えて

0

あなたはselectループの実行専用のスレッドがあると仮定します。スレッドをリアルタイムスケジューリングクラスに入れます。 Appleのサンプルコードは次のとおりです。

#include <mach/mach.h> 
#include <mach/mach_time.h> 
#include <pthread.h> 

void move_pthread_to_realtime_scheduling_class(pthread_t pthread) 
{ 
    mach_timebase_info_data_t timebase_info; 
    mach_timebase_info(&timebase_info); 

    const uint64_t NANOS_PER_MSEC = 1000000ULL; 
    double clock2abs = ((double)timebase_info.denom/(double)timebase_info.numer) * NANOS_PER_MSEC; 

    thread_time_constraint_policy_data_t policy; 
    policy.period  = 0; 
    policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work 
    policy.constraint = (uint32_t)(10 * clock2abs); 
    policy.preemptible = FALSE; 

    int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()), 
        THREAD_TIME_CONSTRAINT_POLICY, 
        (thread_policy_t)&policy, 
        THREAD_TIME_CONSTRAINT_POLICY_COUNT); 
    if (kr != KERN_SUCCESS) { 
     mach_error("thread_policy_set:", kr); 
     exit(1); 
    } 
} 

続きを読むTechnical Note TN2169: High Precision Timers in iOS/OS X

+1

これは何が違いますか?これは、マイクロ秒ではなく秒単位の粒度を考えると、過度に思えます。ドキュメントでは、「リアルタイムスケジューリングクラスのスレッドは、ファーストクラスの治療を受け、実行する必要があるときはいつでも行頭に移動します」と述べています。私のMacBookProには、バグが発生したときにアイドリング状態にある4つの物理コアがあります。他のスレッドが優先されるので、 'select()'が余分な9秒間ハングアップすると思う理由はありません。 – Pol

+0

違いが出るかどうかは分かりません。私は試してみる価値があると思うので、投稿しました。あなたがそれを試して、それが助けにならなかったら、私に知らせて、私は別の提案をします。 –

関連する問題