2016-07-01 14 views
-2

Я пытаюсь сделать программу, которая должна периодически запускать 2 задачи. То есть, например, запустите задачу 1 каждые 10 секунд и запустите задачу 2 каждые 20 секунд.C++ thread, который запускает несколько потоков

Я хочу создать два потока, каждый с таймером. Тема 1 запускает новый поток с заданием 1 каждые 10 секунд. и Thread 2 запускает новый поток с задачей 2 каждые 20 секунд.

Мое сомнение в том, как запустить новую задачу 1, если предыдущая задача 1 еще не закончена?

while (true) 
{ 
    thread t1 (task1); 
    this_thread::sleep_for(std::chrono::seconds(10)); 
    t1.join(); 
} 

Я пытался это сделать, но таким образом он только запустит новую задачу 1, когда предыдущий закончит.

EDIT:

В основном я хочу реализовать планировщик задач. Запуск задачи1 каждые X секунд. Запуск задачи2 каждые Y секунд. Я думал, в чем-то вроде этого:

thread t1 (timer1); 
thread t2 (timer2); 


void timer1() 
{ 
    while (true) 
    { 
     thread t (task1); 
     t.detach() 
     sleep(X); 
    } 

} 

то же самое для Таймер2 и task2

+2

Пожалуйста, отправьте сообщение [MCVE]. Что такое 'task1'? –

+0

Это важно? Я еще не реализовал задачу1. Но это просто простая функция для вычисления некоторых значений и хранения в базе данных. – jcmpoliveira

+0

Вам нужно, чтобы одновременно выполнялись две задачи1? Не могли бы вы уйти с одним потоком task1, где если task1 заканчивается раньше, поток спит до тех пор, пока время не запустится иначе, иначе цикл и повторный запуск? – user4581301

ответ

0

Вы хотите, чтобы избежать использования thread::join() это, по определению, ждет нить до конца. Вместо этого используйте thread::detach перед сном, поэтому его не нужно ждать.

я предлагаю читать на нем http://www.cplusplus.com/reference/thread/thread/detach/

+1

Я бы не стал вслепую рекомендовать использовать 'detach', потому что это может быть очень опасно без особого использования или дополнительной синхронизации с гарантируйте, что все работает правильно. –

+0

Итак, как бы вы это реализовали? – jcmpoliveira

+1

@jcmpoliveira В настоящее время недостаточно информации для предоставления соответствующего ответа. –

1

Может быть, вы могли бы создать periodic_task обработчика, который отвечает за планирование одну задачи каждые t секунд. А затем вы можете запустить periodic_task с определенной функцией и продолжительностью времени из любого места, где вы хотите в своей программе.

Ниже я что-то набросал. Один правильный выбор - отсоединить поток и позволить ему работать вечно. Другим является включение отмены, чтобы позволить родительскому потоку отменять/присоединяться. Я включил функциональность, чтобы позволить последней (хотя вы все еще можете просто отсоединить/забыть).

#include <condition_variable> 
#include <functional> 
#include <iostream> 
#include <mutex> 
#include <thread> 

class periodic_task 
{ 
    std::chrono::seconds d_; 
    std::function<void()> task_; 
    std::mutex mut_; 
    std::condition_variable cv_; 
    bool cancel_{false}; 

public: 
    periodic_task(std::function<void()> task, std::chrono::seconds s) 
     : d_{s} 
     , task_(std::move(task)) 
     {} 

    void 
    operator()() 
    { 
     std::unique_lock<std::mutex> lk{mut_}; 
     auto until = std::chrono::steady_clock::now(); 
     while (true) 
     { 
      while (!cancel_ && std::chrono::steady_clock::now() < until) 
       cv_.wait_until(lk, until); 
      if (cancel_) 
       return; 
      lk.unlock(); 
      task_(); 
      lk.lock(); 
      until += d_; 
     } 
    } 

    void cancel() 
    { 
     std::unique_lock<std::mutex> lk{mut_}; 
     cancel_ = true; 
     cv_.notify_one(); 
    } 
}; 

void 
short_task() 
{ 
    std::cerr << "short\n"; 
} 

void 
long_task(int i, const std::string& message) 
{ 
    std::cerr << "long " << message << ' ' << i << '\n'; 
} 

int 
main() 
{ 
    using namespace std::chrono_literals; 
    periodic_task task_short{short_task, 7s}; 
    periodic_task task_long{[](){long_task(5, "Hi");}, 13s}; 
    std::thread t1{std::ref(task_short)}; 
    std::this_thread::sleep_for(200ms); 
    std::thread t2{std::ref(task_long)}; 
    std::this_thread::sleep_for(1min); 
    task_short.cancel(); 
    task_long.cancel(); 
    t1.join(); 
    t2.join(); 
} 
+0

Привет, спасибо. Но таким образом он запускает только одно задание, которое заканчивается предыдущим. Правильно? – jcmpoliveira

+0

@jcmpoliveira: Верно. Если это не то, что вы хотите, возможно, вы можете изменить это, чтобы сделать именно то, что вы хотите.Этот ответ показывает, как использовать мьютексы и condition_variables для установления какой-либо связи между потоками, независимо от сложности. –

+0

Но в чем смысл мьютексов здесь? Поскольку потоки t1 и t2 не будут конкурировать за доступ к этим ресурсам. Правильно? t1 и t2 работают в двух разных объектах класса: периодическая_таска – jcmpoliveira