c# - 如何在不阻塞所有(或其他一些)的情况下由任何并发请求触发一次?
问题描述
我知道使用lock
来确保一段代码一次只能由一个线程/请求/执行流运行。但我不太确定如何确保在不阻塞某些线程/请求的情况下只触发一次事件。以下是我尝试帮助减少被阻止的并发请求数量的方法:
static bool _isTriggered;
static bool _isTriggering;
static object _o = new object();
void _someMethod(){
if(_isTriggered || _isTriggering) return;
lock(_o){
if(_isTriggered) return;
_isTriggering = true;
//do some long running task by triggering an event for all registered
//handlers to do their own jobs ...
//...
_isTriggered = true;
_isTriggering = false;
}
}
有多个线程或请求_someMethod
同时访问它。所以你可以看到可能有一些请求通过了第一次检查但被lock
. 当第一次运行时lock
,所有其他人(通过第一次检查但之前被阻止)将逐个运行该部分,但由于第二次if
检查将立即返回。(确保事件只触发一次)。
lock
如果所有请求都应该通过代码的锁定部分运行,那就太好了。但是在这里我只需要其中一个来运行该部分,所有其他都应该忽略(并且根本不应该被阻止)。
您是否有任何代码解决方案可以帮助减少被阻止请求的数量(甚至没有请求被阻止)?
更新
是否会确保只运行一次(通过检查):
ConcurrentDictionary<int, bool> _dict = ...;
if(!_dict.AddOrUpdate(someKey, false, (key, vl) => true)){
//...
}
如果它.AddOrUpdate
总是false
第一次返回(作为附加值),那将符合我的要求,因为所有下一个调用都应该调用更新回调并返回true
(这将绕过if
检查)。
解决方案
您是否可以创建一个变量int i = 0
,然后每当线程到达临界区时,它会尝试int result = Interlocked.CompareExchange(ref i, 1, 0)
?然后 if result == 0
,这意味着你的线程正在初始化,否则它不是。
在这种情况下需要考虑的一些事情是
- 其他线程是否必须等待临界区完成初始化,或者即使临界区尚未完成它们也可以继续?这可能意味着对象未初始化并且处于某种不一致的状态。如果他们确实必须等待,也许您可以使用 Lazy 或 LazyInitializer 代替。
- 还有另一种方法来运行这个初始化吗?也许在应用程序启动时运行它会是一个更好的选择,而不是在多线程场景中懒惰地运行。
CompareExchange
编辑:如果我应用该方法,您的代码可能如下所示:
static int i = 0;
void _someMethod(){
int result = Interlocked.CompareExchange(ref i, 1, 0);
if(result != 0) return;
//do some long running task by triggering an event for all registered
//handlers to do their own jobs ...
//...
}
}
只要确保如果您以后i
因为任何其他原因决定访问,您总是通过Interlocked
操作来完成,否则您可能会打开潘多拉魔盒。
推荐阅读
- python - 如何在使用自定义 test_step() 评估 Keras 中使用自定义 train_step() 的模型时设置“training=False”?
- wordpress - 使用插件重定向整个网站(wordpress)还是使用托管公司(godaddy)更好
- maven - -Dcucumber.options 被 mvn 测试忽略
- c# - 带句点的 ASP Net Core 十进制输入变成整数
- git - Git:如何在不暂存文件进行删除的情况下取消跟踪文件
- javascript - javascript深度克隆无法正常工作
- oracle - 在 WebLogic 12c 服务器上启动管理服务器时出错
- excel - 转置一列并保持相对值
- elasticsearch - 从观察者 api 中的 ctx.payload 循环返回的文档数量增加 - Elasticsearch
- python - 使用 for 循环保存具有不同名称的多个图像