2017-12-07 7 views
1

私はC++でスレッドプールを作成しようとしています。コードはOSXでは正常に動作しますが、Linuxでは奇妙な動作が発生しています。 少しのデバッグの後、問題がstd :: condition_variable :: wait_untilの呼び出しによって間違った方法で実行されているに違いないことがわかりました。C++ wait_until奇妙なタイムアウト動作

#include <mutex> 
#include <chrono> 
#include <iostream> 
#include <memory> 
#include <condition_variable> 
#include <thread> 

using namespace std; 

typedef std::chrono::steady_clock       my_clock; 
typedef std::chrono::duration<float, std::ratio<1> >  seconds_duration; 
typedef std::chrono::time_point<my_clock, seconds_duration> timepoint; 

timepoint my_begin = my_clock::now(); 

float timepointToFloat(timepoint time) { 
    return time.time_since_epoch().count() - my_begin.time_since_epoch().count(); 
} 

void printNow(std::string mess) { 
    timepoint now = my_clock::now(); 
    cout << timepointToFloat(now) << " " << mess << endl;; 
}; 

void printNow(std::string mess, timepoint time) { 
    timepoint now = my_clock::now(); 
    cout << timepointToFloat(now) << " " << mess << " " << timepointToFloat(time) << endl;; 
}; 

int main() { 
    mutex _global_mutex; 
    condition_variable _awake_global_execution; 
    auto check_predicate = [](){ 
    cout << "predicate called" << endl; 
    return false; 
    }; 

    while (true) { 
    { // Expected to loop every three seconds 
     unique_lock<mutex> lock(_global_mutex); 
     timepoint planned_awake = my_clock::now() + seconds_duration(3); 
     printNow("wait until", planned_awake); 
     _awake_global_execution.wait_until(lock, planned_awake, check_predicate); 
    } 
    printNow("finish wait, looping"); 
    } 

    return 0; 
} 

は、しかし、時々私は出力として得る:コード付き

私はループが3秒ごとにループされることを期待を下回る

<X> wait until <X+3> 
predicate called 
(...hangs here for a long time) 

(Xは数字です)、タイムアウトは3秒後に予定されていないようです。場合によっては代わりに、私は得る:

<X> wait until <X+3> 
predicate called 
predicate called 
<X> finish wait, looping 
<X> wait until <X+3> (another loop) 
predicate called 
predicate called 
<X> finish wait, looping 
(...continue looping without waiting) 

これはタイムアウトがわずかな秒数の後に予定されているようです。私はタイムアウトのタイムポイントで何かを台無しにしていると思うが、私が間違っていることを理解できない。

このコードは、Linux(Ubuntu 16.04、gcc 5.4、 "g ++ main.cc -std = C++ 11 -pthread"でコンパイルされている)の間にOSXでうまく動作します。奇妙な行動。

どうすれば動作させることができますか?あなたの時計の期間に、あなたのタイムアウトをキャストする

+0

あなたが待つ前に、あなたが待っているものはまだ起きていないことを確認する必要があります。待つことを決断する前に、あなたが待っていることがすでに起こっていることを確認する必要があります。条件変数はステートレスであり、あなたが何を待っているのか、それが起こったのかどうかは分かりません。それはあなたの仕事を追跡することです。 –

+0

あなたのタイムアウトをあなたの時計の持続時間にキャストしようとしましたか?:: chrono :: duration_cast (seconds_duration(3)) ' –

答えて

0

試してみてください。

auto planned_awake = my_clock::now() + 
        std::chrono::duration_cast<my_clock::duration>(secon‌​ds_duration(3)); 
+0

ありがとうございました!私は以前、次のようにキャストしようとしました: "timepoint plans_awake = my_clock :: now()+ std :: chrono :: duration_cast (secon ds_duration(3));" でも違いはありません。代わりに、timeキーワードの代わりにautoキーワードを使用しています。しかし、なぜ? – stavoltafunzia

+0

私は分かりませんが、異なる期間を操作することはうまく機能し、変換を狭めることで失敗しますが、time_pointsはそれほど敏感ではありません。これは、あなたが '' amy_clock :: time_point ''を使うとうまくいくでしょう。 –