FtpServer
FtpServer copied to clipboard
The semaphore has been disposed.
I get error
The semaphore has been disposed.
Could you help to understend the reason of the error? After error Program has critical error.
<Exception>
<ExceptionType>System.ObjectDisposedException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The semaphore has been disposed.</Message>
<StackTrace>
at System.Threading.SemaphoreSlim.CheckDispose()
at System.Threading.SemaphoreSlim.Release(Int32 releaseCount)
at FubarDev.FtpServer.Networking.PausableFtpService.<>c__DisplayClass18_0.<StartAsync>b__0(FtpServiceStatus status)
at System.Progress`1.InvokeHandlers(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
</StackTrace>
<ExceptionString>System.ObjectDisposedException: The semaphore has been disposed.
at System.Threading.SemaphoreSlim.CheckDispose()
at System.Threading.SemaphoreSlim.Release(Int32 releaseCount)
at FubarDev.FtpServer.Networking.PausableFtpService.<>c__DisplayClass18_0.<StartAsync>b__0(FtpServiceStatus status)
at System.Progress`1.InvokeHandlers(Object state)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()</ExceptionString>
</Exception>
We have the same case when the connection was closed immediately after opening. I guess the Progress implementation is to blame here:
using (var semaphore = new SemaphoreSlim(0, 1))
{
_jobPaused = new CancellationTokenSource();
_task = RunAsync(
new Progress<FtpServiceStatus>(
status =>
{
Status = status;
if (status == FtpServiceStatus.Running)
{
// ReSharper disable once AccessToDisposedClosure
semaphore.Release();
}
}));
await semaphore.WaitAsync(cancellationToken);
}
The Progress
uses SyncronizationContext.Post
to pass progress data and, theoretically, can be invoked after the semaphore will be disposed.
I have encountered the same issue. In my case, the problem occurred in conjunction with SslStreamConnectionAdapter
(explicit encryption).
This exception encountered before: Status must be Running, Stopped, or Paused, but was ReadyToRun.
System.InvalidOperationException:
at FubarDev.FtpServer.Networking.PausableFtpService+<StopAsync>d__19.MoveNext (FubarDev.FtpServer, Version=3.1.1.0, Culture=neutral, PublicKeyToken=null)
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at FubarDev.FtpServer.ConnectionHandlers.SslStreamConnectionAdapter+<StopAsync>d__12.MoveNext (FubarDev.FtpServer, Version=3.1.1.0, Culture=neutral, PublicKeyToken=null)
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at FubarDev.FtpServer.FtpConnection+<StopAsync>d__61.MoveNext (FubarDev.FtpServer, Version=3.1.1.0, Culture=neutral, PublicKeyToken=null)
Immediately after that the same exception occured: The semaphore has been disposed.
System.ObjectDisposedException:
at System.Threading.SemaphoreSlim.CheckDispose (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at System.Threading.SemaphoreSlim.Release (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at FubarDev.FtpServer.Networking.PausableFtpService+<>c__DisplayClass18_0.<StartAsync>b__0 (FubarDev.FtpServer, Version=3.1.1.0, Culture=neutral, PublicKeyToken=null)
at System.Progress`1.InvokeHandlers (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
at System.Threading.ThreadPoolWorkQueue.Dispatch (System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e)
This class extension helps to solve this problem:
internal class SemaphoreSlimExt : SemaphoreSlim
{
public SemaphoreSlimExt(int initialCount)
: base(initialCount)
{
}
public SemaphoreSlimExt(int initialCount, int maxCount)
: base(initialCount, maxCount)
{
}
public bool IsDisposed { get; internal set; }
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
IsDisposed = true;
}
}
and after
using (var semaphore = new SemaphoreSlimExt(0, 1))
{
_jobPaused = new CancellationTokenSource();
_task = RunAsync(
new Progress<FtpServiceStatus>(
status =>
{
Status = status;
if (status == FtpServiceStatus.Running && **!semaphore.IsDisposed**)
{
// ReSharper disable once AccessToDisposedClosure
semaphore?.Release();
}
}));
var res = semaphore.WaitAsync(cancellationToken);
res.Wait();
}