Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/facebook/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用线程以定时间隔调用函数_C++_Multithreading_Pthreads_Scheduled Tasks - Fatal编程技术网

C++ 使用线程以定时间隔调用函数

C++ 使用线程以定时间隔调用函数,c++,multithreading,pthreads,scheduled-tasks,C++,Multithreading,Pthreads,Scheduled Tasks,我正在制作一个模拟器,用来测试一个非常简单的机器人的学生代码。我需要定期在不同的线程上运行两个函数(更新机器人传感器和机器人位置)。我当前的实现处理器效率很低,因为它有一个线程专门用于简单地递增数字以跟踪代码中的位置。我最近的理论是,我可以使用睡眠来给出传感器更新值和机器人位置之间的时间延迟。我的第一个问题是:这是否有效?第二:除了测量时钟周期而不是秒之外,还有什么方法可以做一件简单的事情吗?是的,你的理论是正确的。您可以使用sleep在线程执行函数之间设置一些延迟。效率取决于您可以选择多大的延

我正在制作一个模拟器,用来测试一个非常简单的机器人的学生代码。我需要定期在不同的线程上运行两个函数(更新机器人传感器和机器人位置)。我当前的实现处理器效率很低,因为它有一个线程专门用于简单地递增数字以跟踪代码中的位置。我最近的理论是,我可以使用睡眠来给出传感器更新值和机器人位置之间的时间延迟。我的第一个问题是:这是否有效?第二:除了测量时钟周期而不是秒之外,还有什么方法可以做一件简单的事情吗?

是的,你的理论是正确的。您可以使用sleep在线程执行函数之间设置一些延迟。效率取决于您可以选择多大的延迟来获得所需的结果您必须解释实施的细节。例如,我们不知道两个线程是否相互依赖(在这种情况下,您必须注意同步,这会破坏一些周期)

通过等待类似互斥对象的对象来休眠线程通常是有效的。一种常见的模式是等待具有超时的互斥锁。当达到超时值时,间隔即告结束。当互斥被释放时,它是线程终止的信号

伪代码:

void threadMethod() {
  for(;;) {
    bool signalled = this->mutex.wait(1000);
    if(signalled) {
      break; // Signalled, owners wants us to terminate
    }

    // Timeout, meaning our wait time is up
    doPeriodicAction();
  }
}

void start() {
  this->mutex.enter();
  this->thread.start(threadMethod);
}

void stop() {
  this->mutex.leave();
  this->thread.join();
}
在Windows系统上,超时通常以毫秒为单位,精确到大约16毫秒以内(
timeBeginPeriod()
可能可以改善这一点)。我不知道CPU周期触发的同步原语。有一种称为“关键部分”的轻量级互斥体,在委托给OS线程调度器之前,它会使CPU旋转数千个周期。在这段时间内,它们相当准确

在Linux系统上,准确度可能会稍高一些(高频定时器或无滴答的内核),除了互斥外,还有类似于Windows关键部分的“futex”(快速互斥)



我不确定我是否掌握了您想要实现的目标,但是如果您想测试学生代码,您可能希望使用虚拟时钟并自己控制时间的流逝。例如,通过调用学生必须提供的
processInputs()
decideMovements()
方法。每次调用后,都会有一个时隙。

此C++11代码使用
std::chrono::high_resolution_clock
测量亚秒计时,并使用
std::thread
运行三个线程。
std::this_thread::sleep_for()
函数用于在指定时间内睡眠

#include <iostream>
#include <thread>
#include <vector>
#include <chrono>

void seconds()
{
    using namespace std::chrono;

    high_resolution_clock::time_point t1, t2; 
    for (unsigned i=0; i<10; ++i) {
        std::cout << i << "\n";
        t1 = high_resolution_clock::now();
        std::this_thread::sleep_for(std::chrono::seconds(1)); 
        t2 = high_resolution_clock::now();
        duration<double> elapsed = duration_cast<duration<double> >(t2-t1);
        std::cout << "\t( " << elapsed.count() << " seconds )\n";
    }
}
int main()
{
    std::vector<std::thread> t;

    t.push_back(std::thread{[](){ 
        std::this_thread::sleep_for(std::chrono::seconds(3)); 
        std::cout << "awoke after 3\n"; }});
    t.push_back(std::thread{[](){ 
        std::this_thread::sleep_for(std::chrono::seconds(7)); 
        std::cout << "awoke after 7\n"; }});
    t.push_back(std::thread{seconds});

    for (auto &thr : t)
        thr.join();
}
我的机器上的输出:

0
    ( 1.00014 seconds)
1
    ( 1.00014 seconds)
2
awoke after 3
    ( 1.00009 seconds)
3
    ( 1.00015 seconds)
4
    ( 1.00011 seconds)
5
    ( 1.00013 seconds)
6
awoke after 7
    ( 1.0001 seconds)
7
    ( 1.00015 seconds)
8
    ( 1.00014 seconds)
9
    ( 1.00013 seconds)

其他可能感兴趣的C++11标准功能包括和。

这里有一种方法。我正在使用C++11、线程、原子和高精度时钟。调度程序将回调一个需要dt秒的函数,这是自上次调用以来经过的时间。如果回调函数返回false,则可以通过调用的stop()方法停止循环

计划程序代码

#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
#include <system_error>

class ScheduledExecutor {
public:
    ScheduledExecutor()
    {}
    ScheduledExecutor(const std::function<bool(double)>& callback, double period)
    {
        initialize(callback, period);
    }
    void initialize(const std::function<bool(double)>& callback, double period)
    {
        callback_ = callback;
        period_ = period;
        keep_running_ = false;
    }

    void start()
    {
        keep_running_ = true;
        sleep_time_sum_ = 0;
        period_count_ = 0;
        th_ = std::thread(&ScheduledExecutor::executorLoop, this);
    }

    void stop()
    {
        keep_running_ = false;
        try {
            th_.join();
        }
        catch(const std::system_error& /* e */)
        { }
    }

    double getSleepTimeAvg()
    {
        //TODO: make this function thread safe by using atomic types
        //right now this is not implemented for performance and that
        //return of this function is purely informational/debugging purposes
        return sleep_time_sum_ / period_count_;
    }

    unsigned long getPeriodCount()
    {
        return period_count_;
    }

private:
    typedef std::chrono::high_resolution_clock clock;
    template <typename T>
    using duration = std::chrono::duration<T>;

    void executorLoop()
    {
        clock::time_point call_end = clock::now();
        while (keep_running_) {
            clock::time_point call_start = clock::now();
            duration<double> since_last_call = call_start - call_end;

            if (period_count_ > 0 && !callback_(since_last_call.count()))
                break;

            call_end = clock::now();

            duration<double> call_duration = call_end - call_start;
            double sleep_for = period_ - call_duration.count();
            sleep_time_sum_ += sleep_for;
            ++period_count_;
            if (sleep_for > MinSleepTime)
                std::this_thread::sleep_for(std::chrono::duration<double>(sleep_for));
        }
    }

private:
    double period_;
    std::thread th_;
    std::function<bool(double)> callback_;
    std::atomic_bool keep_running_;

    static constexpr double MinSleepTime = 1E-9;

    double sleep_time_sum_;
    unsigned long period_count_;
};
bool worldUpdator(World& w, double dt)
{
    w.update(dt);
    return true;
}

void main() {
    //create world for your simulator
    World w(...);

    //start scheduler loop for every 2ms calls
    ScheduledExecutor exec;
    exec.initialize(
        std::bind(worldUpdator, std::ref(w), std::placeholders::_1), 
            2E-3);
    exec.start();

    //main thread just checks on the results every now and then
    while (true) {
        if (exec.getPeriodCount() % 10000 == 0) {
            std::cout << exec.getSleepTimeAvg() << std::endl;
        }
    }
}
#包括
#包括
#包括

#包括,等等问题。

你能更详细地解释一下你希望做什么吗?为什么传感器和位置有不同的螺纹?这两个线程是否以任何方式相互依赖?除非测试代码真的很繁重,否则我怀疑您是否需要认真考虑优化测试代码的效率。您可以使用
sleep()
,是的。但在大多数情况下,这可能是一个非常糟糕的主意(你可能会忙着等待)。更合适的方法是使用定时信号量/条件变量。
bool worldUpdator(World& w, double dt)
{
    w.update(dt);
    return true;
}

void main() {
    //create world for your simulator
    World w(...);

    //start scheduler loop for every 2ms calls
    ScheduledExecutor exec;
    exec.initialize(
        std::bind(worldUpdator, std::ref(w), std::placeholders::_1), 
            2E-3);
    exec.start();

    //main thread just checks on the results every now and then
    while (true) {
        if (exec.getPeriodCount() % 10000 == 0) {
            std::cout << exec.getSleepTimeAvg() << std::endl;
        }
    }
}