c++ - 确保只有一个函数实例在运行?

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

我刚刚开始并发编程。我的问题很可能很常见,但由于我找不到合适的名称,所以无法通过 google 搜索。

我有一个 C++ UWP 应用程序,我尝试在其中应用 MVVM 模式,但我猜想该模式甚至是 UWP 都不相关。

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

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 函数每分钟或响应用户请求在计时器上调用。我想要的是:如果在启动或请求新的刷新操作时已经在进行刷新操作,则放弃第二个并等待第一个完成(或超时)。换句话说,我不想将所有对 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。我猜问题出在 unique_lock 析构函数对 mutexunlock,它发生在协程的延续和不同的线程(其他比它最初锁定的那个)。

使用 Visual C++ 2017。

最佳答案

使用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;
   }
}

两个可能的改进:包装 isRunning.store在 RAII 类中并使用 std::shared_ptr<std::atomic_bool>如果 atomic_bool 的生命周期是范围内的。

关于c++ - 确保只有一个函数实例在运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43757096/

相关文章:

java - Android Studio OpenCV 示例

c++ - 缓存的不可变值 : avoid lock

c++ - Qt 线程计算输出到 GUI 中的自己的小部件?

关于继承成员地址的 C++ 标准

c++ - 可以将类对象创建为仅左值吗?

堆的 C++ 损坏

c++ - 如何特征默认构造函数是私有(private)的

.net - 如何分别渲染用户控件

C++:如何区分对类成员的引用和对普通变量的引用?

C++ vector push_back 方法和临时对象创建