我正在查看.NET 4.0的System.Threading.Tasks.TaskScheduler.Id实现,并看到以下代码:
[__DynamicallyInvokable]
public int Id
{
[__DynamicallyInvokable]
get
{
if (this.m_taskSchedulerId == 0)
{
int num = 0;
do
{
num = Interlocked.Increment(ref s_taskSchedulerIdCounter);
}
while (num == 0);
Interlocked.CompareExchange(ref this.m_taskSchedulerId, num, 0);
}
return this.m_taskSchedulerId;
}
}
为什么msft比较互锁后的num == 0? Interlocked.Increment()的实现表示它返回递增的值(递增后),因此检查零似乎是不合适的(除非您的计数器包裹,但如果发生这种情况,您还会遇到更大的问题)这里没有解决。
如果我这样做,我只会这样做:
public int Id
{
get
{
if(m_taskSchedulerId==0)
{
var result = Interlocked.Increment(ref s_taskSchedulerIdCounter);
Interlocked.CompareExchange(ref m_taskSchedulerId, result, 0);
}
return m_taskSchedulerId;
}
}
答案 0 :(得分:8)
但如果发生这种情况你会遇到更大的问题
不,这就是他们这样做的确切原因。来自Reference Source:
public Int32 Id
{
get
{
if (m_taskSchedulerId == 0)
{
int newId = 0;
// We need to repeat if Interlocked.Increment wraps around and returns 0.
// Otherwise next time this scheduler's Id is queried it will get a new value
do
{
newId = Interlocked.Increment(ref s_taskSchedulerIdCounter);
} while (newId == 0);
Interlocked.CompareExchange(ref m_taskSchedulerId, newId, 0);
}
return m_taskSchedulerId;
}
}
答案 1 :(得分:1)
不变量是Id
永远不会返回0,因为0在内部用于指示应该初始化该值。如果Id
为0,则下次查询时它将是不同的值。