2017-03-16 131 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