2017-03-16 133 views
1

我想编写C#代码,做类似这样的Java代码:什么是C#相当于Java的getAndSet

public class Syncer { 
    private AtomicBoolean syncInProgress = AtomicBoolean(false); 

    // Data is synced periodically and on user request 
    // and these two calls may overlap 
    public void SyncData() { 
     if (flag.getAndSet(true)) { 
      return ; 
     } 

     // Sync data... 
     // It is enough that one thread is syncing data 

     flag.getAndSet(false); 
    } 
} 
+0

你尝试过这么远吗? – ArgusMagnus

+0

我写的代码不是线程安全的 – Uros

+2

不熟悉C#中的原子操作,但是'Interlocked.Exchange'? https://msdn.microsoft.com/en-us/library/bb337971(v=vs.110).aspx – chris

回答

6

我与克里斯,Interlocked.Exchange(ref Int32, Int32)同意,只有0中,1是更换。

的方法的描述:

设置一个32位带符号整数为指定的值,并返回原来的值,作为一个原子操作。

AtomicBoolean.getAndSet()描述:

原子方式设置为给定的值,并返回原来的值。

可悲的是没有Interlocked.Exchange()bool(并注意Interlocked.Exchange<T>()是引用类型!)

在问题中给出的代码:

public class Syncer 
{ 
    private int flag = 0; 

    // Data is synced periodically and on user request 
    // and these two calls may overlap 
    public void SyncData() 
    { 
     if (Interlocked.Exchange(ref flag, 1) == 1) 
     { 
      return; 
     } 

     // Sync data... 
     // It is enough that one thread is syncing data 

     Interlocked.Exchange(ref flag, 0); 
    } 
} 
+0

你能分享一些代码吗? – Uros

+0

@Uros Done ..... – xanatos

+0

请注意,如果您的'// Sync data ...'区域正在更新引用类型,您可能需要查看使用'Interlocked.Exchange '一个比较和交换循环...这个方法可能不像第一眼看上去那样线程安全。 –

2

Interlocked.Exchange是你在找什么对于。不幸的是,如上所述,你不能用它与bool,这是一个耻辱。一种替代方法是使用this answer中指出的int过载。

该解决方案的“幻数” -ness一直困扰个人我一点点。但有你就可以说,否则就像一个bool引用类型的方式:

public sealed class RefBool 
{ 
    public static implicit operator bool(RefBool value) 
    { 
     return value != null; 
    } 

    public static implicit operator RefBool(bool value) 
    { 
     return value ? RefBool.True : RefBool.False; 
    } 

    public static bool operator true(RefBool value) 
    { 
     return value != null; 
    } 

    public static bool operator false(RefBool value) 
    { 
     return value == null; 
    } 

    public static readonly RefBool True = new RefBool(); 
    public static readonly RefBool False = null; 

    private RefBool() 
    { 
    } 
} 

现在,您的类可以是这样的:

public class Syncer 
{ 
    private RefBool mIsSyncInProgress = false; 

    public void SyncData() 
    { 
     if (Interlocked.Exchange(ref mIsSyncInProgress, true)) 
     { 
      return; 
     } 

     // Sync data... 
     // It is enough that one thread is syncing data 

     Interlocked.Exchange(ref mIsSyncInProgress, false); 
    } 
} 

我觉得这更容易在使用场所阅读。我不觉得这个解决方案是完美的,因为RefBool类有点奇怪。

你应该注意到我用null的真实状态。这是为了确保类型RefBool的变量只能是truefalse。如果我用了两个不同的实例来表示truefalse,然后RefBool也可能是null,这将是一个不确定的状态。

这样做的缺点是,ToString不正确的工作(这就是为什么我没有打扰覆盖它)。

+0

很伤心你不能接受两个答案。我还没有测试过你的解决方案。 – Uros

1

我建议你使用Montior.TryEnter(Object, Boolean),这个最适合你的问题/例子。

但这可以写更好/更紧凑,Monitor.TryEnter(Object)我会留给下面的第一个代码示例建议)。

public class Syncer 
{ 
    private object lockObject = new object(); 

    // Data is synced periodically and on user request 
    // and these two calls may overlap 
    public void SyncData() { 
     bool syncInProgress = false; 
     try { 
      Monitor.TryEnter(lockObject, ref syncInProgress); 
      if (syncInProgress) { 
       // The critical section. 

       // Sync data... 
       // It is enough that one thread is syncing data 
      } 
      else { 
       // The lock was not acquired. 
       return; 
      } 
     } 
     finally { 
      // Ensure that the lock is released. 
      if (syncInProgress) { 
       Monitor.Exit(lockObject); 
      } 
     } 
    } 
} 

清洁例如:

public class Syncer 
{ 
    private object lockObject = new object(); 

    // Data is synced periodically and on user request 
    // and these two calls may overlap 
    public void SyncData() { 
     if(Monitor.TryEnter(lockObject)){ 
      try { 
       // The critical section. 

       // Sync data... 
       // It is enough that one thread is syncing data 
      } 
      finally { 
       // Ensure that the lock is released. 
       Monitor.Exit(lockObject); 
      } 
     } 
     else { 
      // The lock was not acquired. 
      return; 
     } 
    } 
} 
+0

'syncInProgress'应该是一个局部变量,不是字段,否则:T1会取锁,将'syncInProgress'设置为'true',T2尝试取锁,失败,将'syncInProgress'设置为'false'并返回。现在T1退出,但'syncInProgress'是'false',所以没有发布。 – xanatos

+0

@xanatos你是绝对正确的,我相应地更新了我的答案。谢谢! – Cyrus