如何通过多次调用异步函数来避免竞争条件?

时间:2018-04-20 23:42:09

标签: c++ uwp task c++-cx ppl

在下面的示例中,对HandleChangesAsync的调用是在异步任务中通过事件处理程序进行的。

我担心有一个潜在的竞争条件,其中一个线程正在HandleChangesAsync中执行create_task块。当发生这种情况时,OnSomethingChanged处理程序触发,第二个线程最终在HandleChangesAsync中执行相同的create_task块,

问题 - 假设这种担忧是合法的,那么消除这种竞争条件的正确方法是什么?

void MyClass::DoStuffAsync()
{    
    WeakReference weakThis(this);
    create_task(DoMoreStuffAsync())
        .then([weakThis]())
    {
        auto strongThis = weakThis.Resolve<HomePromotionTemplateViewModel>();
        if (strongThis)
        {
            strongThis->RegisterForChanges();
            strongThis->HandleChangesAsync();
        }
    });
}

void MyClass::RegisterForChanges()
{    
    // Attach event handler to &MyClass::OnSomethingChanged
}

void MyClass::OnSomethingChanged()
{
    HandleChangesAsync();
}

void MyClass::HandleChangesAsync()
{    
    WeakReference weakThis(this);
    create_task(DoMoreCoolStuffAsync())
        .then([weakThis]())
    {
        // do stuff 
    });
}

1 个答案:

答案 0 :(得分:0)

避免竞争条件的一种简单方法是将您正在创建的任务链接到HandleChangesAsync,这样您就可以确定它们将一个接一个地执行。

为此,您需要在班级中添加新成员,例如

task<void> _handleChangesAsyncTask;
std::mutex _lock;

然后HandleChangesAsync中的代码变为:

void MyClass::HandleChangesAsync()
{    
    std::lock_guard<std::mutex> lk(_lock);
    WeakReference weakThis(this);
    handleChangesAsyncTask = handleChangesAsyncTask.then(
        []()
    {
        return create_task(DoMoreCoolStuffAsync());
    }).then(
        [weakThis]()
    {
        // do stuff 
    });
}

注意互斥锁以防止对_handleChangesAsyncTask的并发访问。