结构和结构集合的易失性

irr*_*iss 4 .net c# multithreading volatile concurrentdictionary

我想用网络智慧澄清一些关于.net中多线程的时刻.互联网上有很多关于它的东西但是我无法找到我的问题的好答案.

假设我们希望在同类线程中保持安全状态.简单的情况是当state为int时:

class Class1
{
    volatile int state = 0;

    public int State
    {
        get
        {
            return state;
        }
    }

    public Action<int> StateUpdated;

    public void UpdateState(int newState)
    {
        state = newState;

        if (StateUpdated != null)
            StateUpdated(newState);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,'volatile'应该足够了.无论什么线程需要获取当前状态,它都可以使用永远不会被缓存的"State"属性.无论线程想要更​​新状态,它都可以使用"UpdateState"安全地进行更新.

但是,如果州是一个结构,该怎么办?完全'锁定'是唯一的方法吗?附带问题:变量是否仍然可以缓存在锁内?

struct StateData
{
    //some fields
}

class Class1
{
    StateData state;

    public StateData State
    {
        get
        {
            return state;
        }
    }

    public Action<StateData> StateUpdated;

    public void UpdateState(StateData newState)
    {
        state = newState;

        if (StateUpdated != null)
            StateUpdated(newState);
    }
}
Run Code Online (Sandbox Code Playgroud)

最后的主要问题是:此代码是否足以在多线程环境中管理状态对象的集合?或者可能存在一些隐藏的问题.

public struct StateData
{
    //some fields
}

public delegate void StateChangedHandler(StateData oldState, StateData newState);

class Class1
{
    ConcurrentDictionary<string, StateData> stateCollection = new ConcurrentDictionary<string, StateData>();

    public StateData? GetState(string key)
    {
        StateData o;

        if (stateCollection.TryGetValue(key, out o))
            return o;
        else
            return null;
    }

    public StateChangedHandler StateUpdated;

    void UpdateState(string key, StateData o)
    {
        StateData? prev = null;

        stateCollection.AddOrUpdate(key, o,
            (id, old) =>
            {
                prev = old;

                return o;
            }
            );

        if (prev != null && StateUpdated != null)
            StateUpdated(prev.Value, o);
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢你的回答.

Pet*_*iho 5

但是,如果州是一个结构,该怎么办?完全'锁定'是唯一的方法吗?

volatile关键字仅适用于可以原子更新的类型,例如引用类型变量,指针和基元类型.

但是,请注意,volatile除了访问标记变量之外,还提供了一些保证.特别是,在写入带volatile标记的存储器位置之前发生的所有对存储器的写入都将从相同volatile标记的存储器位置读取之后从存储器读取的任何代码中看到.

从理论上讲,这意味着您可以使用volatile字段为其他内存位置提供类似易失性的行为.

但实际上,仍然存在一个问题:对相同内存位置的新写入可能会也可能不会显示,当然并非所有写入都可以原子方式完成.因此,这种使用volatile实际上只适用于可能被标记为易失性的其他内存位置,即使这样也不能确保您不会获得比标记的内存位置更新的volatile.

这是一个很长的说法,你应该使用lock并完成它.:)

附带问题:变量是否仍然可以缓存在锁内?

我不完全确定你的意思是什么.但总的来说:只要这些优化不会影响单个线程中代码的观察行为,就允许编译器进行优化.如果您考虑的缓存类型不违反此规则,则可能允许.否则就不会.

这段代码是否足以在多线程环境中管理状态对象的集合?

发布的代码似乎很好,至少就确保字典始终提供连贯的状态值而言.