一、背景
这个标题起的有点标题党的嫌疑[捂脸],这个事情的原委是这样的,有个Web API的站点在本地使用Release模式Run的时候出现问题,但是使用Debug模式则不会。通过打日志定位到问题在如下的这个代码这里:
private static int _flag;
public void ExactlyOnceMethod()
{
var original = Interlocked.Exchange(ref _flag, 1);
if (original == _flag)
{
// 1.重复进入
}
else
{
// 2.第一次进入
}
}
理论上,会有一次请求进入到2中,但是实际问题是全部都进入到了1中。
二、代码描述
这个代码很简单,就做了2个事情,1是使用Interlocked.Exchange将_flag变量进行赋值。2是将Interlocked.Exchange操作后返回的原始值与_flag变量进行对比,如果相等说明这个变量已经被修改过了,表示这里是重入了。如果不是则说明第一次进入此方法。
关于Interlocked.Exchange的解释,见微软官网文档,传送门在此:https://msdn.microsoft.com/zh-cn/library/d3fxt78a.aspx
三、越分析越黑暗
好了,咋一看了好几分钟,也没看出有什么不妥的地方,那么首先就往多线程问题上考虑了。但是这里唯一的共享变量就是_flag,走的又是CAS操作,在这里不存在多线程问题。