简体   繁体   English

重置线程的休眠时间

[英]Resetting sleeping time of a thread

Suppose to have a thread like this 假设有一个像这样的线程

void mythread()
{
  int res;
  while(1) {
    {
       boost::lock_guard<boost::mutex> lock(mylock);
       res = do_my_stuff();
    }
    boost::this_thread::sleep(boost::posix_time::seconds(5));
  }
}

and that the thread is currently sleeping. 而且线程正在休眠。 If something happens outside of the thread, I'd like to be able to increase the sleep time. 如果在线程之外发生了某些事情,我希望能够增加睡眠时间。

What is the best way to do it? 最好的方法是什么?

Using a condition_variable to signal changes to the deadline 使用condition_variable发出更改截止日期的信号

This has the benefit of supporting scenarios where the timeout is shortened : 这有利于支持缩短超时的方案:

See it Live On Coliru 看到Live On Coliru

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

namespace demo
{
    namespace chrono = std::chrono;

    using our_clock = chrono::system_clock;

    struct Worker
    {
        mutable std::mutex _mx;

        // shared, protected by _mx:
        our_clock::time_point _deadline; 
        mutable std::condition_variable _cv;

        Worker(our_clock::time_point deadline) : _deadline(deadline) {}

        void operator()() const {
            std::unique_lock<std::mutex> lk(_mx);
            _cv.wait_until(lk, _deadline, [this] 
                    { 
                        std::cout << "worker: Signaled\n";
                        auto now = our_clock::now();
                        if (now >= _deadline)
                            return true;
                        std::cout << "worker: Still waiting " << chrono::duration_cast<chrono::milliseconds>(_deadline - now).count() << "ms...\n"; 
                        return false;
                    });
            std::cout << "worker: Done\n";
        }
    };
}

int main()
{
    using namespace demo;

    Worker worker(our_clock::now() + chrono::seconds(2));
    auto th = std::thread(std::cref(worker));

    // after 2 seconds, update the timepoint
    std::this_thread::sleep_for(chrono::seconds(1));

    {
        std::lock_guard<std::mutex> lk(worker._mx);
        std::cout << "Updating shared delay value..." << "\n";

        worker._deadline = our_clock::now() + chrono::seconds(1);
        worker._cv.notify_all();
    }

    th.join();
}

C++11 standard library (no signaling) C ++ 11标准库(无信令)

Here's a standard-library only approach which uses no synchronization around the deadline. 这是一种仅限标准库的方法,在截止日期前不使用同步。

I'd have preferred to use atomic time_point for the deadline value itself, but that's not supported. 我更倾向于使用原子time_point作为截止时间值本身,但这不受支持。 Next best thing would have been shared_ptr<time_point> (with std::atomic_load / atomic_store ) but my compiler's library doesn't implement this yet ( grrr ). 接下来最好的事情就是shared_ptr<time_point> (使用std::atomic_load / atomic_store )但我的编译器库还没有实现它( grrr )。

So, instead, I share the 'offset' since a start time: 所以,相反,我从开始时间开始分享'偏移':

#include <thread>
#include <chrono>
#include <iostream>
#include <atomic>

namespace demo
{
    namespace chrono = std::chrono;

    using our_clock = chrono::system_clock;
    using shared_delay = std::atomic<our_clock::duration>;

    void worker(our_clock::time_point const start, shared_delay const& delay)
    {
        for (our_clock::time_point deadline; our_clock::now() < (deadline = start + delay.load());)
        {
            std::cout << "worker: Sleeping for " << chrono::duration_cast<chrono::milliseconds>(deadline - our_clock::now()).count() << "ms...\n";
            std::this_thread::sleep_until(deadline);
        }

        std::cout << "worker: Done\n";
    }
}

int main()
{
    using namespace demo;

    shared_delay delay(chrono::seconds(2));
    auto th = std::thread(worker, our_clock::now(), std::cref(delay));

    // after 2 seconds, update the timepoint
    std::this_thread::sleep_for(chrono::seconds(1));
    std::cout << "Updating shared delay value..." << "\n";
    delay.store(chrono::seconds(3));

    th.join();
}

See it Live on Coliru 在科利鲁看到它

Here is a quick and dirty method: 这是一个快速而肮脏的方法:

volatile bool someCondition = false;

void callFromOtherThread(bool x) {
  boost::lock_guard<boost::mutex> lock(mylock2);
  someCondition = x;
}

void mythread()
{
  int res;
  while(1) {
    bool keepwaiting = false;
    {
      boost::lock_guard<boost::mutex> lock(mylock2);
      keepwaiting = someCondition;
    }
    if (!keepwaiting) {
       boost::lock_guard<boost::mutex> lock(mylock);
       res = do_my_stuff();
    }
    boost::this_thread::sleep(boost::posix_time::seconds(5));
  }
}

When your thread finished sleeping, it checks it 'something else' happened, and if it did, it skips 'do_my_stuff()' and goes back to sleep again. 当你的线程完成睡眠时,它会检查它发生了“其他事情”,如果它发生了,它会跳过'do_my_stuff()'并再次回到睡眠状态。

I suspect with somewhat more information about your use case it might be possible to rewrite things to use a condition variable. 我怀疑有关您的用例的更多信息,可能可以重写事物以使用条件变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM