using System.Collections.Generic;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
return selectedText;
}
+
+ public static ReadLockTransaction BeginReadTransaction(this ReaderWriterLockSlim lockObj)
+ => new ReadLockTransaction(lockObj);
+
+ public static WriteLockTransaction BeginWriteTransaction(this ReaderWriterLockSlim lockObj)
+ => new WriteLockTransaction(lockObj);
+
+ public static UpgradeableReadLockTransaction BeginUpgradeableReadTransaction(this ReaderWriterLockSlim lockObj)
+ => new UpgradeableReadLockTransaction(lockObj);
}
}
/// <summary>
/// innerDictionary の排他制御のためのロックオブジェクト
/// </summary>
- private object lockObject = new object();
+ private ReaderWriterLockSlim lockObject = new ReaderWriterLockSlim();
/// <summary>
/// オブジェクトが破棄された否か
return Task.Run(() =>
{
- Task<MemoryImage> cachedImageTask = null;
- lock (this.lockObject)
+ if (force)
{
- innerDictionary.TryGetValue(address, out cachedImageTask);
+ using (this.lockObject.BeginWriteTransaction())
+ this.innerDictionary.Remove(address);
+ }
- if (cachedImageTask != null)
- {
- if (force)
- {
- this.innerDictionary.Remove(address);
- cachedImageTask = null;
- }
- else
- return cachedImageTask;
- }
+ using (var transaction = this.lockObject.BeginUpgradeableReadTransaction())
+ {
+ Task<MemoryImage> cachedImageTask;
+ if (innerDictionary.TryGetValue(address, out cachedImageTask))
+ return cachedImageTask;
cancelToken.ThrowIfCancellationRequested();
- var imageTask = this.FetchImageAsync(address, cancelToken);
- this.innerDictionary[address] = imageTask;
+ using (transaction.UpgradeToWriteLock())
+ {
+ var imageTask = this.FetchImageAsync(address, cancelToken);
+ this.innerDictionary[address] = imageTask;
- return imageTask;
+ return imageTask;
+ }
}
}, cancelToken);
}
public MemoryImage TryGetFromCache(string address)
{
- lock (this.lockObject)
+ using (this.lockObject.BeginReadTransaction())
{
Task<MemoryImage> imageTask;
if (!this.innerDictionary.TryGetValue(address, out imageTask) ||
public void CancelAsync()
{
- lock (this.lockObject)
+ using (this.lockObject.BeginWriteTransaction())
{
var oldTokenSource = this.cancelTokenSource;
this.cancelTokenSource = new CancellationTokenSource();
{
this.CancelAsync();
- lock (this.lockObject)
+ using (this.lockObject.BeginWriteTransaction())
{
foreach (var item in this.innerDictionary)
{
}
this.innerDictionary.Clear();
- this.cancelTokenSource.Dispose();
}
+
+ this.cancelTokenSource.Dispose();
+ this.lockObject.Dispose();
}
this.disposed = true;
<Compile Include="Models\UserTimelineTabModel.cs" />
<Compile Include="MouseWheelMessageFilter.cs" />
<Compile Include="NotifyPropertyChangedBase.cs" />
+ <Compile Include="ReaderWriterLockTransaction.cs" />
<Compile Include="SendErrorReportForm.cs">
<SubType>Form</SubType>
</Compile>
--- /dev/null
+// OpenTween - Client of Twitter
+// Copyright (c) 2016 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
+// All rights reserved.
+//
+// This file is part of OpenTween.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program. If not, see <http://www.gnu.org/licenses/>, or write to
+// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+// Boston, MA 02110-1301, USA.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OpenTween
+{
+ public sealed class ReadLockTransaction : IDisposable
+ {
+ private readonly ReaderWriterLockSlim lockObj;
+
+ public ReadLockTransaction(ReaderWriterLockSlim lockObj)
+ {
+ if (lockObj == null)
+ throw new ArgumentNullException(nameof(lockObj));
+
+ this.lockObj = lockObj;
+ this.lockObj.EnterReadLock();
+ }
+
+ public void Dispose()
+ => this.lockObj.ExitReadLock();
+ }
+
+ public sealed class WriteLockTransaction : IDisposable
+ {
+ private readonly ReaderWriterLockSlim lockObj;
+
+ public WriteLockTransaction(ReaderWriterLockSlim lockObj)
+ {
+ if (lockObj == null)
+ throw new ArgumentNullException(nameof(lockObj));
+
+ this.lockObj = lockObj;
+ this.lockObj.EnterWriteLock();
+ }
+
+ public void Dispose()
+ => this.lockObj.ExitWriteLock();
+ }
+
+ public sealed class UpgradeableReadLockTransaction : IDisposable
+ {
+ private readonly ReaderWriterLockSlim lockObj;
+
+ public UpgradeableReadLockTransaction(ReaderWriterLockSlim lockObj)
+ {
+ if (lockObj == null)
+ throw new ArgumentNullException(nameof(lockObj));
+
+ this.lockObj = lockObj;
+ this.lockObj.EnterUpgradeableReadLock();
+ }
+
+ public WriteLockTransaction UpgradeToWriteLock()
+ => new WriteLockTransaction(this.lockObj);
+
+ public void Dispose()
+ => this.lockObj.ExitUpgradeableReadLock();
+ }
+}