我有一个多执行绪 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();
}
}
0 评论