如何安排要在将来运行的操作

时间:2019-09-04 13:54:13

标签: c++ boost

我有一个TaskManager类,其中包含一系列任务。每次弹出并执行下一个任务。

class TaskManager
{
    TaskQueue m_queue;

    svc_tasks()
    {
         while (!m_queue.empty())
         {
             Task* task = m_queue.pop();
             task->execute();
         }
    }
};

在“任务”中,我想暂停至少SLEEP_TIME_MS毫秒。在此暂停期间,我想开始执行下一个任务。暂停结束后,我想再次将任务放入队列。

class Task
{
    int m_phase = -1;

    execute()
    {
        m_phase++;

        switch(m_phase)
        {
         case 0:
             ...
             do_pause(SLEEP_TIME_MS);
             return;
         case 1:
             ...
             break;
        }
    }
};

std(C ++ 17)中是否有我可以使用的调度程序,当SLEEP_TIME_MS通过时会调用处理程序函数吗?

谢谢您的建议

1 个答案:

答案 0 :(得分:1)

您可以将boost::asio::high_resolution_timerasync_wait方法一起使用。

每次要安排将任务推入队列的操作时,都必须:

  1. 创建high_resolution_timer
  2. 调用expires_after,它指定到期时间(SLEEP_TIME_MS),即何时调用处理程序。在此处理程序中,您将任务推入队列。
  3. 与您的处理程序通话async_wait

如果我们假设execute方法返回bool来指示任务是否已完成(所有阶段均已执行),则可以将其重写为以下内容:

     while (!m_queue.empty()) // this condition should be changed
     {
         Task* task = m_queue.pop();
         bool finished = task->execute();
         if (!finished)
            scheduler works here - start async_wait with handler
     }

如果我的理解正确,您想在SLEEP_TIME_MS到期时将任务推入队列,因此当队列为空时您就不能中断循环,因为您必须等待待完成的任务完成。您可以引入stop标志。并按需中断循环。


下面,我放了一段代码,该代码的工作方式与您描述的方式相同(希望如此):

struct Scheduler {
    Scheduler(boost::asio::io_context& io)
    : io(io) {}

    boost::asio::io_context& io;

    template<class F>
    void schedule (F&& handler) {
        auto timer = std::make_shared<boost::asio::high_resolution_timer>(io);
        timer->expires_after(std::chrono::milliseconds(5000)); // SLEEP_TIME_MS 
        timer->async_wait(
            [timer,handler](const boost::system::error_code& ec) {
                handler();
            });
    }
};

struct Task  {
    int phase = -1;

    bool execute() {
        ++phase;
        std::cout << "phase: " << phase << std::endl;
        if (phase == 0) {
            return false;
        }
        else {

        }
        return true;
    }
};

struct TaskManager {
    Scheduler s;
    std::queue<std::shared_ptr<Task>> tasks;
    std::mutex tasksMtx;
    std::atomic<bool> stop{false};

    TaskManager(boost::asio::io_context& io) : s(io) {
        for (int i = 0; i < 5; ++i)
            tasks.push(std::make_shared<Task>());
    }

    void run() {
        while (true) {
            if (stop)
                break;

            {
                std::lock_guard<std::mutex> lock{tasksMtx};
                if (tasks.empty())
                    continue;
            }

            std::shared_ptr<Task> currTask = tasks.front();
            tasks.pop();

            bool finished = currTask->execute();
            if (!finished)
                s.schedule( [this, currTask](){ insertTaskToVector(std::move(currTask)); } );
        }
    }

    template<class T>
    void insertTaskToVector(T&& t) {
        std::lock_guard<std::mutex> lock{tasksMtx};
        tasks.push(std::forward<T>(t));
    }
};

int main() {
    boost::asio::io_context io;
    boost::asio::io_context::work work{io};
    std::thread th([&io](){ io.run();});
    TaskManager tm(io);
    tm.run();