1

std::thread を使用してタイマーを作成しました-これは次のようになります。

TestbedTimer::TestbedTimer(char type, void* contextObject) : 
  Timer(type, contextObject) {
    this->active = false;
}

TestbedTimer::~TestbedTimer(){
    if (this->active) {
        this->active = false;

        if(this->timer->joinable()){

            try {
                this->timer->join();
            } catch (const std::system_error& e) {
                std::cout << "Caught system_error with code " << e.code()  << 
                              " meaning " << e.what() << '\n';
            }
        }

       if(timer != nullptr) {
           delete timer;
       }
    }
}

void TestbedTimer::run(unsigned long timeoutInMicroSeconds){
    this->active = true;
    timer = new std::thread(&TestbedTimer::sleep, this, timeoutInMicroSeconds);
}

void TestbedTimer::sleep(unsigned long timeoutInMicroSeconds){
    unsigned long interval = 500000;

    if(timeoutInMicroSeconds < interval){
        interval = timeoutInMicroSeconds;
    }

    while((timeoutInMicroSeconds > 0) && (active == true)){
        if (active) {
            timeoutInMicroSeconds -= interval;
            /// set the sleep time
            std::chrono::microseconds duration(interval);
            /// set thread to sleep
            std::this_thread::sleep_for(duration);
        }
    }

    if (active) {
       this->notifyAllListeners();
    } 
}

void TestbedTimer::interrupt(){
    this->active = false;
}

タイマーを短い間隔でスリープさせ、アクティブフラグが変更されたかどうかを確認するため、この種の実装にはあまり満足していません(ただし、 sleep_for 呼び出しを中断できないため、より良い解決策はわかりません)。ただし、プログラムのコア ダンプに次のメッセージが表示されます。

thread is joinable
Caught system_error with code generic:35 meaning Resource deadlock avoided
thread has rejoined main scope
terminate called without an active exception
Aborted (core dumped)

このエラーを調べたところ、別のスレッドを待機しているスレッドがあるようです (リソースのデッドロックの理由)。しかし、私はこれがどこで起こっているのかを正確に知りたいと思っています。C++ コードで C ライブラリ (pthreads を使用) を使用しています。このライブラリは、他の機能の中でもデーモンとして実行するオプションを提供していますが、これが std::thread コードに干渉するのではないかと心配しています。これをデバッグする最良の方法は何ですか?

helgrind を使用しようとしましたが、これはあまり役に立ちませんでした (エラーは見つかりません)。

ティア

** 編集: 上記のコードは実際には模範的なコードではありませんが、ルーティング デーモン用に記述したコードです。ルーティング アルゴリズムはリアクティブであり、目的の宛先へのルートがない場合にのみルート ディスカバリを開始し、ネットワーク内のすべてのホストのルーティング テーブルを構築しようとはしません。ルート ディスカバリがトリガーされるたびに、タイマーが開始されます。タイマーが切れると、デーモンに通知され、パケットは破棄されます。基本的には、次のようになります。

void Client::startNewRouteDiscovery(Packet* packet) {
    AddressPtr destination = packet->getDestination();
    ...
    startRouteDiscoveryTimer(packet);
    ...
}

void Client::startRouteDiscoveryTimer(const Packet* packet) {
    RouteDiscoveryInfo* discoveryInfo = new RouteDiscoveryInfo(packet);
    /// create a new timer of a certain type
    Timer* timer = getNewTimer(TimerType::ROUTE_DISCOVERY_TIMER, discoveryInfo);
    /// pass that class as callback object which is notified if the timer expires (class implements a interface for that)
    timer->addTimeoutListener(this);
    /// start the timer
    timer->run(routeDiscoveryTimeoutInMilliSeconds * 1000);

    AddressPtr destination = packet->getDestination();
    runningRouteDiscoveries[destination] = timer;
}

タイマーが切れた場合、次のメソッドが呼び出されます。

void Client::timerHasExpired(Timer* responsibleTimer) {
    char timerType = responsibleTimer->getType();
    switch (timerType) {
        ...
        case TimerType::ROUTE_DISCOVERY_TIMER:
            handleExpiredRouteDiscoveryTimer(responsibleTimer);
            return;
        ....
        default:
            // if this happens its a bug in our code
            logError("Could not identify expired timer");
            delete responsibleTimer;
    }
}

私がやっていることをよりよく理解するのに役立つことを願っています。ただし、追加のコードで質問を肥大化させるつもりはありませんでした。

4

0 に答える 0