简体   繁体   English

满足条件时如何取消std :: async?

[英]How to cancel std::async when condition is met?

I am running an asynchronous task and want to cancel it when a certain condition ( bool ) is met. 我正在运行异步任务,想在满足特定条件( bool )时取消它。

void MyClass::createTask()
{
    this->future = std::async(std::launch::async, [this](){
        while(this->CONDITION == false)
        {
            // do work
        }
    });
}

void MyClass::cancelTask()
{
    this->CONDITION = true;
    this->future.get();
}

Obviously, calling MyClass::cancelTask() would cause a data-race, because this->CONDITION is being written to and read from at the same time. 显然,调用MyClass::cancelTask()会导致数据争用,因为这是同时写入和读取此this->CONDITION So the first thing that came to my mind is to use a std::mutex . 因此,我想到的第一件事就是使用std::mutex However that would mean that the task has to lock and unlock the mutex on every new iteration of the while-loop. 但是,这意味着任务必须在while循环的每次新迭代中锁定和解锁互斥锁。 Since the async task is performance critical, this seems like a bad choice. 由于异步任务对性能至关重要,因此这似乎是一个错误的选择。

Is there a cleaner, and especially a more perfomant way to achieve what I am trying to do? 是否有更清洁的方法,尤其是更人性化的方法来实现我想要做的事情? Switching from std::async to std::thread would be ok if it enabled an efficient solution. 如果启用了有效的解决方案,则可以从std::async切换到std::thread

As far as I know there is no elegant way to close a thread/async task in C++. 据我所知,没有一种优雅的方法可以关闭C ++中的线程/异步任务。

A simple way is to use std::atomic<bool> or std::atomic_flag instead of a mutex. 一种简单的方法是使用std::atomic<bool>std::atomic_flag而不是互斥锁。

If you are familiar with boost library, than you could use boost::thread with interruption_points. 如果您熟悉boost库,则可以将boost::thread与interrupt_points一起使用。

I have a solution for this kind of requeirements. 对于这种要求,我有一个解决方案。 I use std::mutex , std::condition_variable and std::unique_lock<std::mutex> to create tow methods: pauseThread and resumeThread . 我使用std::mutexstd::condition_variablestd::unique_lock<std::mutex>创建两个方法: pauseThreadresumeThread

The idea is use the condition_variable and unique_lock to make the thread wait for a time, for example 5 seconds, and after the time os over the thread continue its execution. 这个想法是使用condition_variableunique_lock使线程等待一段时间,例如5秒,然后在线程上的时间os之后继续执行它。 But, if you want to interrupt the condition_variable you could use its method notify_one() . 但是,如果要中断condition_variable ,则可以使用其方法notify_one()

Using your code, and continue with your idea, i made some changes to your class: 使用您的代码,并继续您的想法,我对您的课程进行了一些更改:

MODIFICATION: I modify the flag bKeepRunning. 修改:我修改了标志bKeepRunning。

MyClass.h MyClass.h

#include <mutex>
#include <chrono>
#include <future>
#include <atomic>

class MyClass
{
    std::atomic<bool> bKeepRunning;

    std::mutex mtx_t;
    std::condition_variable cv_t;
    std::future<void> _future;

public:
    MyClass();
    ~MyClass();

    void createTask();
    void stopTask();

    void pauseThread(int time);
    void resumeThread();

}

MyClass.cpp MyClass.cpp

#include "MyClass.h"

#include <iostream>

using namespace std;

MyClass::MyClass()
{
    bKeepRunning = false;
}

MyClass::~MyClass()
{
}

void MyClass::createTask()
{
    bKeepRunning = true;
    _future = std::async(std::launch::async, [this]() {
        int counter = 0;
        cout << "Thread running" << endl;
        while (bKeepRunning)
        {
            counter++;
            cout << "Asynchronous thread counter = [" << counter << "]" << endl;
            this->pauseThread(5);//Wait for 5 seconds
        }
        cout << "Thread finished." << endl;
    });
}

void MyClass::stopTask()
{
    cout << "Stoping Thread." << endl;
    bKeepRunning = false;
    resumeThread();
}

void MyClass::pauseThread(int time)
{
    std::unique_lock<std::mutex> lck_t(mtx_t);
    cv_t.wait_for(lck_t, chrono::seconds(time));
}

void MyClass::resumeThread()
{
    cout << "Resumming thread" << endl;
    cv_t.notify_one();
}

I made a console sample to show how it works: 我制作了一个控制台示例来演示其工作原理:

Main.cpp Main.cpp的

#include <iostream>
#include <sstream>
#include <string>

#include "MyClass.h"

using namespace std;

int main(int argc, char* argv[])
{
    MyClass app;
    char line[80];

    cout << "Press Enter to stop thread." << endl;
    app.createTask();

    cin.getline(line,80);
    app.stopTask();
}

If you need some other period of time to pause your thread, you can try to change the interval and time of chrono::seconds(time) to, for example, chrono::milliseconds(time) that is using milliseconds.+ 如果您需要其他时间来暂停线程,则可以尝试将chrono::seconds(time)的间隔和时间更改为例如使用毫秒的chrono::milliseconds(time)

At the end, if you execute this sample, you could get an output like: 最后,如果执行此示例,您将获得类似以下的输出:

在此处输入图片说明

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

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