1

System.Threading.Tasks.TaskScheduler.Id の .NET 4.0 の実装を見ていると、次のコードが表示されます。

[__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;
            }
        }
4

2 に答える 2

8

しかし、それが起こった場合、あなたはより大きな問題を抱えています

いいえ、それが彼らがこれを行う正確な理由です。参照元から:

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;
    }
}
于 2012-09-28T07:06:27.050 に答える
1

値を初期化する必要があることを示すために 0 が内部的に使用されるため、不変条件はId0 を返さないことです。これIdまで 0 だった場合、次にクエリを実行すると、別の値になります。

于 2012-09-28T07:08:18.880 に答える