确保只有一个函数实例是 运行?
Ensuring that only one instance of a function is running?
我刚刚接触并发编程。很可能我的问题很常见,但由于找不到合适的名称,所以我不能 google。
我有一个 C++ UWP 应用程序,我尝试在其中应用 MVVM 模式,但我猜想该模式甚至是 UWP 都不相关。
首先,我有一个公开操作的服务接口:
struct IService
{
virtual task<int> Operation() = 0;
};
当然,我提供了一个具体的实现,但与本次讨论无关。该操作可能很长-运行:它发出 HTTP 请求。
然后我有一个使用该服务的 class(同样,省略了不相关的细节):
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
}
按原文编辑post:我在上面的代码片段中注释掉了这行,因为它没有区别。问题依旧。
但是断言当然失败了:unlock of unowned mutex
。我猜问题是 mutex
的 unlock
by unique_lock
析构函数,它发生在协程的延续和不同的线程上(除了它最初被锁定的线程) .
使用 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 class 中,并在 atomic_bool
的生命周期内使用 std::shared_ptr<std::atomic_bool>
。
我刚刚接触并发编程。很可能我的问题很常见,但由于找不到合适的名称,所以我不能 google。
我有一个 C++ UWP 应用程序,我尝试在其中应用 MVVM 模式,但我猜想该模式甚至是 UWP 都不相关。
首先,我有一个公开操作的服务接口:
struct IService
{
virtual task<int> Operation() = 0;
};
当然,我提供了一个具体的实现,但与本次讨论无关。该操作可能很长-运行:它发出 HTTP 请求。
然后我有一个使用该服务的 class(同样,省略了不相关的细节):
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
}
按原文编辑post:我在上面的代码片段中注释掉了这行,因为它没有区别。问题依旧。
但是断言当然失败了:unlock of unowned mutex
。我猜问题是 mutex
的 unlock
by unique_lock
析构函数,它发生在协程的延续和不同的线程上(除了它最初被锁定的线程) .
使用 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 class 中,并在 atomic_bool
的生命周期内使用 std::shared_ptr<std::atomic_bool>
。