我有一個多執行緒 UI 應用程式,它啟動多個后臺執行緒。許多這些執行緒執行如下所示的代碼:
public void Update(){
if(Dispatcher.HasShutdownStarted()) return;
Dispatcher.Invoke(()=>{...});
...
}
然后我有時可能會有一個執行緒執行下面的代碼
pubic void Shutdown(){
if(Dispatcher.HasShutdownStarted()) return;
Dispatcher.InvokeShutdown();
}
問題是有時一個執行緒在Dispatcher.InvokeShutdown()另一個執行緒執行之后Dispatcher.HasShutdwonStarted()但在它到達之前執行Dispatcher.Invoke(()=>{...})。這意味著,一旦 Dispatcher 開始關閉,就會有一個執行緒嘗試在 Dispatcher 上執行 lambda。那就是我遇到例外的時候。對此的最佳解決方案是什么?
uj5u.com熱心網友回復:
您面臨的問題是在執行 Invoke 中的代碼之前檢查了 HasShutdownStarted(因為它在調度程式上排隊)
我認為更好的方法是在呼叫內部檢查它,這樣你就不需要任何鎖。
public void Update(){
Dispatcher.Invoke(()=>
{
if(Dispatcher.HasShutdownStarted()) return;
...
});
}
uj5u.com熱心網友回復:
一種選擇是使用任何物件創建同步塊,例如:
// Define property
private readonly object _thisLock = new object();
然后在你只需要一個執行緒的代碼中使用synchronized關鍵字
public void SetTps(decimal limit)
{
if (_limit == limit || limit <= 0)
return;
// This is the important part
lock (_thisLock)
{
_limit = limit;
ResetTps();
}
}
鎖有點重,您也可以嘗試使用semaphore 或 semaphore slim:
// First you create the semaphore
semaphore = new SemaphoreSlim(0, 3);
// Then you solicit with wait
semaphore.Wait();
// Do all your work that needs only one resource at the time
// After you release the semaaphore
semaphore.Release();
編輯
幾乎忘記了,對于您的情況,在讀取次數很多而寫入次數不多的情況下,您可以使用ReaderWriterLockSlim
public class SynchronizedCache
{
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
private Dictionary<int, string> innerCache = new Dictionary<int, string>();
public int Count
{ get { return innerCache.Count; } }
public string Read(int key)
{
cacheLock.EnterReadLock();
try
{
return innerCache[key];
}
finally
{
cacheLock.ExitReadLock();
}
}
public void Add(int key, string value)
{
cacheLock.EnterWriteLock();
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
}
public bool AddWithTimeout(int key, string value, int timeout)
{
if (cacheLock.TryEnterWriteLock(timeout))
{
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
return true;
}
else
{
return false;
}
}
public AddOrUpdateStatus AddOrUpdate(int key, string value)
{
cacheLock.EnterUpgradeableReadLock();
try
{
string result = null;
if (innerCache.TryGetValue(key, out result))
{
if (result == value)
{
return AddOrUpdateStatus.Unchanged;
}
else
{
cacheLock.EnterWriteLock();
try
{
innerCache[key] = value;
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Updated;
}
}
else
{
cacheLock.EnterWriteLock();
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Added;
}
}
finally
{
cacheLock.ExitUpgradeableReadLock();
}
}
public void Delete(int key)
{
cacheLock.EnterWriteLock();
try
{
innerCache.Remove(key);
}
finally
{
cacheLock.ExitWriteLock();
}
}
public enum AddOrUpdateStatus
{
Added,
Updated,
Unchanged
};
~SynchronizedCache()
{
if (cacheLock != null) cacheLock.Dispose();
}
}
對于您的情況,它看起來像:
public void Update(){
cacheLock.EnterReadLock();
try {
if(Dispatcher.HasShutdownStarted()) return;
} finally {
cacheLock.ExitReadLock();
}
Dispatcher.Invoke(()=>{...});
...
}
和
pubic void Shutdown(){
cacheLock.EnterWriteLock();
try {
if(Dispatcher.HasShutdownStarted()) return;
Dispatcher.InvokeShutdown();
} finally {
cacheLock.ExitWriteLock();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/391651.html
上一篇:多執行緒和指令序列
下一篇:了解C#中的信號量
