如何在不使用Lock的情况下使操作组原子化

时间:2019-06-05 08:54:50

标签: c# thread-safety readerwriterlockslim

我有一个state变量,其关注域为thread-safe,并使用fresh保留了ReaderWriterLockSlim。自从我使用以来,我对所有字段的访问都得到了细化他们分别放在其他地方。

虽然可以单独访问字段,但是我还需要使几个操作原子化。在这种情况下,我是否需要额外的lock

我有一个状态变量,该变量已经包含thread-safe个字段:

internal class State {

        private ReaderWriterLockSlim lck = new ReaderWriterLockSlim();

        private bool cmd_PopUp;

        private bool cmd_Shutdown;
        private bool cmd_Delay;



        public bool CMD_PopUp {
            get {
                try {
                    this.lck.EnterReadLock();
                    return this.cmd_PopUp;
                } finally {

                    this.lck.ExitReadLock();
                }

            }
            set {
                try {
                    this.lck.EnterWriteLock();
                    this.cmd_PopUp = value;
                } finally {

                    this.lck.ExitWriteLock();
                }
            }

        }

 //same goes for the other booleans
}

我已经具有线程安全性,并且我确保线程从内存中读取而不是从本地缓存中读取。但是,我需要执行多个原子操作。

原子操作

public async Task Run(State state)
{

     while(true)
        {
        //do i need a lock here
                        if (state.CMD_Delay) {
                            state.CMD_Delay = false;
                            state.CMD_PopUp = false;
        //end of potential lock ?
                        } else if (state.CMD_Shutdown) { //same here
                            state.CMD_PopUp = false;
                            state.CMD_Shutdown = false;
                            await SomeAction();
                        }
        }
}

正如您在我的while中看到的那样,我有一个if-else,在这里我需要使操作组成为原子操作。应该使用额外的lock还是有其他轻量级解决方案?

1 个答案:

答案 0 :(得分:1)

重新使用您现有的锁对我来说最有意义:

internal class State
{
  ...
  public void SetDelayState()
  {
    try {
      this.lck.EnterWriteLock();
      this.cmd_Delay = false;
      this.cmd_PopUp = false;
    } finally {
      this.lck.ExitWriteLock();
    }
  }
  public void SetShutdownState()
  {
    try {
      this.lck.EnterWriteLock();
      this.cmd_PopUp = false;
      this.cmd_Shutdown = false;
    } finally {
      this.lck.ExitWriteLock();
    }
  }
}

换句话说,将所有原子操作移为您的State类型的成员。

侧面说明:您几乎可以肯定不需要读/写锁。读卡器/写卡器锁只能在以下条件的所有为真时使用:

  • 某些代码路径是只读的,而另一些则是读/写的。
  • 读者远远超过作家。
  • 有大量连续的读者。

如果其中的任何个都不正确,那么lock是更好的选择。