Merge pull request #24 from paulcbetts/sync-reads-ios
Ensure no concurrent access to NSMutableData
This commit is contained in:
Коммит
c7839b04f1
|
@ -65,6 +65,9 @@
|
|||
<Compile Include="..\Shared\ConcatenatingStream.cs">
|
||||
<Link>ConcatenatingStream.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\AsyncLock.cs">
|
||||
<Link>AsyncLock.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
||||
</Project>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<DefineConstants>DEBUG; UIKIT</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
|
@ -29,7 +29,6 @@
|
|||
</CustomCommands>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
|
@ -41,6 +40,7 @@
|
|||
<Command type="BeforeBuild" command="make AFNetworking.dll" workingdir="${SolutionDir}" />
|
||||
</CustomCommands>
|
||||
</CustomCommands>
|
||||
<DefineConstants>UIKIT</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.MonoTouch.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -59,5 +59,8 @@
|
|||
<Compile Include="..\Shared\ConcatenatingStream.cs">
|
||||
<Link>ConcatenatingStream.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\AsyncLock.cs">
|
||||
<Link>AsyncLock.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
|
||||
namespace ModernHttpClient
|
||||
{
|
||||
// Straight-up thieved from http://www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitives.aspx
|
||||
public sealed class AsyncLock
|
||||
{
|
||||
readonly SemaphoreSlim m_semaphore = new SemaphoreSlim(1, 1);
|
||||
readonly Task<IDisposable> m_releaser;
|
||||
|
||||
public AsyncLock()
|
||||
{
|
||||
m_releaser = Task.FromResult((IDisposable)new Releaser(this));
|
||||
}
|
||||
|
||||
public Task<IDisposable> LockAsync()
|
||||
{
|
||||
var wait = m_semaphore.WaitAsync();
|
||||
return wait.IsCompleted ?
|
||||
m_releaser :
|
||||
wait.ContinueWith((_, state) => (IDisposable)state,
|
||||
m_releaser.Result, CancellationToken.None,
|
||||
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
|
||||
}
|
||||
|
||||
sealed class Releaser : IDisposable
|
||||
{
|
||||
readonly AsyncLock m_toRelease;
|
||||
internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }
|
||||
public void Dispose() { m_toRelease.m_semaphore.Release(); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace ModernHttpClient
|
|||
{
|
||||
readonly CancellationTokenSource cts = new CancellationTokenSource();
|
||||
readonly Action onDispose;
|
||||
readonly AsyncLock readLock = new AsyncLock();
|
||||
|
||||
long position;
|
||||
bool closeStreams;
|
||||
|
@ -83,7 +84,15 @@ namespace ModernHttpClient
|
|||
|
||||
Stream stream = Current;
|
||||
if (stream == null) break;
|
||||
int thisCount = await stream.ReadAsync(buffer, offset, count);
|
||||
|
||||
var thisCount = default(int);
|
||||
#if UIKIT
|
||||
using (await readLock.LockAsync()) {
|
||||
thisCount = await stream.ReadAsync(buffer, offset, count);
|
||||
}
|
||||
#else
|
||||
thisCount = await stream.ReadAsync(buffer, offset, count);
|
||||
#endif
|
||||
|
||||
result += thisCount;
|
||||
count -= thisCount;
|
||||
|
@ -127,7 +136,15 @@ namespace ModernHttpClient
|
|||
|
||||
Stream stream = Current;
|
||||
if (stream == null) break;
|
||||
int thisCount = stream.Read(buffer, offset, count);
|
||||
|
||||
var thisCount = default(int);
|
||||
#if UIKIT
|
||||
using (readLock.LockAsync().Result) {
|
||||
thisCount = stream.Read(buffer, offset, count);
|
||||
}
|
||||
#else
|
||||
thisCount = stream.Read(buffer, offset, count);
|
||||
#endif
|
||||
|
||||
result += thisCount;
|
||||
count -= thisCount;
|
||||
|
|
Загрузка…
Ссылка в новой задаче