簡體   English   中英

C ++延遲任務

[英]C++ delayed tasks

我想實現一種方法來安排稍后執行的任務。 該接口類似於JavaScript的setTimeout(function, milliseconds)

在我的應用程序中,某些資源由一個線程擁有。 為了避免競爭條件,必須始終從同一個線程訪問它們。 如果其他線程想要訪問資源,則必須將任務對象分派給資源線程。

所以我需要解決的兩個問題是:

  1. 將任務分派給一個線程
  2. 延遲調用

通過使用無消耗隊列快速修復第一個問題,該隊列在消費端具有資源線程。 (我使用TBB的concurrent_bounded_queue。)然而,第二個問題對我來說並不那么明顯。 我可以想到兩個策略:

  1. 為每個任務啟動一個新線程。 該線程將睡眠所需的延遲,然后將任務分派到並發隊列。
  2. 僅啟動一個運行循環的線程,該循環迭代計划的任務,並在等待時間到期時調用它們。

我已經嘗試了這兩種方法,我傾向於支持第一種,因為它簡單可靠,而第二種往往更容易出現微妙的錯誤。 第一種方法將此委托給OS線程調度程序。

但是,第一個解決方案確實會創建大量短期線程,而我通常會聽到重用線程的建議。

手動實現將如下所示。

struct myrunnable {
  uint64_t id_;
  uint64_t stamp_;
  std::function<void()> runnable_;
  uint64_t id() { return id_; }
  uint64_t stamp() { return stamp_; }
  void execute() { if (runnable_) runnable_(); }
};

typedef std::shared_ptr<myrunnable> task_t;
// timestamp_cmp_t - a comparator by timestamp + incrementing task id
typedef tbb::concurrent_blocking_queue<task_t> queue_t;
typedef std::priority_queue<task, timestamp_cmp_t> schedule_t;

uint64_t now(); // a wrapper around gettimeofday(), write yourself

queue_t queue; // inbound concurrent blocking queue not bound in size
schedule_t schedule; // priority queue, a scheduler
// queue_t sink; // optional sink concurrent queue if you don't
                 // want to execute tasks in the scheduler thread context

// now() - a wrapper around gettimeofday(), write yourself
for(;;) { // "termination mark" comments below - exit points
  while (!schedule.empty() && schedule.top().stamp() <= now()) {
    task_t task = schedule.pop();
    task .execute();
    // alternatively sink.push(task) to offload scheduler thread
  }

  if (schedule.empty()) {
    task_t task = queue.pop(); // block on the input queue
    if (!task) return; // scheduler termination mark, empty task
    schedule.push(task);
  } else {
    // Here we are driven by our latency/cpu balance requirements
    // in this example we are ultra low latency and are just spinning CPU
    // and on Linux such thread may need extra tuning to perform consistently.
    // To pace it down one can use TBB's sleep_for() or select() system call

    while (schedule.top().stamp() > now()) {
      task_t task;
      if (queue.try_pop(task)) {
        if (!task) return; // scheduler termination mark, empty task
        schedule.push(task);
      }
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM