确保只有一个函数实例正在运行?

时间:2017-05-03 10:10:12

标签: c++ multithreading c++11 visual-c++ visual-c++-2017

我刚刚进入并发编程。很可能我的问题非常普遍,但由于我找不到一个好名字,我不能谷歌。

我有一个C ++ UWP应用程序,我尝试应用MVVM模式,但我猜这种模式甚至是UWP是不相关的。

首先,我有一个公开操作的服务接口:

struct IService
{
    virtual task<int> Operation() = 0;
};

当然,我提供了一个具体的实现,但它与此讨论无关。该操作可能长时间运行:它发出HTTP请求。

然后我有一个使用该服务的类(同样,省略了不相关的细节):

class ViewModel
{
    unique_ptr<IService> service;
public:
    task<void> Refresh();
};

我使用协同程序:

task<void> ViewModel::Refresh()
{
    auto result = co_await service->Operation();
    // use result to update UI
}

每分钟都会在计时器上调用Refresh函数,或者响应用户请求。我想要的是:如果在启动或请求新操作时刷新操作已在进行中,则放弃第二个操作并等待第一个操作完成(或超时)。换句话说,我不想将所有调用排队到刷新 - 如果调用已在进行中,我宁愿跳过一个调用直到下一个计时器滴答。

我的尝试(可能非常天真)是:

mutex refresh;
task<void> ViewModel::Refresh()
{
    unique_lock<mutex> lock(refresh, try_to_lock);
    if (!lock)
    {
        // lock.release(); commented out as harmless but useless => irrelevant
        co_return;
    }
    auto result = co_await service->Operation();
    // use result to update UI
}

在原帖后编辑:我在上面的代码段中注释掉了这一行,因为它没有任何区别。问题仍然存在。

但当然断言失败了:unlock of unowned mutex。我想这个问题是unlock mutex unique_lock析构函数,它发生在协程的延续和不同的线程(不是最初锁定的那个)上

使用Visual C ++ 2017。

1 个答案:

答案 0 :(得分:1)

使用std::atomic_bool

std::atomic_bool isRunning = false;
if (isRunning.exchange(true, std::memory_order_acq_rel) == false){
   try{
    auto result = co_await Refresh();
    isRunning.store(false, std::memory_order_release);
    //use result 
   }
   catch(...){
     isRunning.store(false, std::memory_order_release);
     throw;
   }
}

两种可能的改进:在RAII类中包裹isRunning.store,如果std::shared_ptr<std::atomic_bool>的范围是有效的,则使用atomic_bool