- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在使用 Starksoft.Net.Ftp 执行异步上传操作。
看起来像这样:
public void UploadFile(string filePath, string packageVersion)
{
_uploadFtpClient= new FtpClient(Host, Port, FtpSecurityProtocol.None)
{
DataTransferMode = UsePassiveMode ? TransferMode.Passive : TransferMode.Active,
FileTransferType = TransferType.Binary,
};
_uploadFtpClient.TransferProgress += TransferProgressChangedEventHandler;
_uploadFtpClient.PutFileAsyncCompleted += UploadFinished;
_uploadFtpClient.Open(Username, Password);
_uploadFtpClient.ChangeDirectoryMultiPath(Directory);
_uploadFtpClient.MakeDirectory(newDirectory);
_uploadFtpClient.ChangeDirectory(newDirectory);
_uploadFtpClient.PutFileAsync(filePath, FileAction.Create);
_uploadResetEvent.WaitOne();
_uploadFtpClient.Close();
}
private void UploadFinished(object sender, PutFileAsyncCompletedEventArgs e)
{
if (e.Error != null)
{
if (e.Error.InnerException != null)
UploadException = e.Error.InnerException;
}
_uploadResetEvent.Set();
}
如您所见,其中有一个 ManualResetEvent,它在类的顶部被声明为私有(private)变量:
private ManualResetEvent _uploadResetEvent = new ManualResetEvent(false);
嗯,感觉只是应该等待上传完成,但是它必须是异步的来报告进度,仅此而已。
现在,这一切正常。如果需要,我有第二种方法可以取消上传。
public void Cancel()
{
_uploadFtpClient.CancelAsync();
}
当上传被取消时,服务器上的一个目录也必须被删除。我也有一个方法:
public void DeleteDirectory(string directoryName)
{
_uploadResetEvent.Set(); // As the finished event of the upload is not called when cancelling, I need to set the ResetEvent manually here.
if (!_hasAlreadyFixedStrings)
FixProperties();
var directoryEmptyingClient = new FtpClient(Host, Port, FtpSecurityProtocol.None)
{
DataTransferMode = UsePassiveMode ? TransferMode.Passive : TransferMode.Active,
FileTransferType = TransferType.Binary
};
directoryEmptyingClient.Open(Username, Password);
directoryEmptyingClient.ChangeDirectoryMultiPath(String.Format("/{0}/{1}", Directory, directoryName));
directoryEmptyingClient.GetDirListAsyncCompleted += DirectoryListingFinished;
directoryEmptyingClient.GetDirListAsync();
_directoryFilesListingResetEvent.WaitOne(); // Deadlock appears here
if (_directoryCollection != null)
{
foreach (FtpItem directoryItem in _directoryCollection)
{
directoryEmptyingClient.DeleteFile(directoryItem.Name);
}
}
directoryEmptyingClient.Close();
var directoryDeletingClient = new FtpClient(Host, Port, FtpSecurityProtocol.None)
{
DataTransferMode = UsePassiveMode ? TransferMode.Passive : TransferMode.Active,
FileTransferType = TransferType.Binary
};
directoryDeletingClient.Open(Username, Password);
directoryDeletingClient.ChangeDirectoryMultiPath(Directory);
directoryDeletingClient.DeleteDirectory(directoryName);
directoryDeletingClient.Close();
}
private void DirectoryListingFinished(object sender, GetDirListAsyncCompletedEventArgs e)
{
_directoryCollection = e.DirectoryListingResult;
_directoryFilesListingResetEvent.Set();
}
由于取消时没有调用上传完成事件,我需要在DeleteDirectory方法中手动设置ResetEvent。
现在,我在这里做什么:我首先列出目录中的所有文件以便删除它们,因为无法删除已填充的文件夹。
此方法 GetDirListAsync 也是异步的,这意味着我需要另一个 ManualResetEvent,因为我不希望表单卡住。
此 ResetEvent 是 _directoryFilesListingResetEvent。它的声明类似于上面的 _uploadResetEvent。
现在,问题是,它转到 _directoryFilesListingResetEvent 的 WaitOne 调用,然后卡住了。出现死锁,表单卡住。 (我在代码中也标出了)
这是为什么呢?我试图移动 _uploadResetEvent.Set() 的调用,但它没有改变。有人看到问题了吗?
当我尝试在没有任何上传的情况下单独调用 DeleteDirectory 方法时,它也能正常工作。我认为问题在于两个 ResetEvents 使用相同的资源或其他东西并且它们自身重叠,我不知道。
感谢您的帮助。
最佳答案
你没有正确使用这个库。您添加的 MRE 会导致死锁。从 _uploadResetEvent.WaitOne() 开始,阻塞了 UI 线程。这通常是非法的,CLR 确保您的 UI 不会通过自己发送消息循环而完全死机。这使它看起来 就像它还活着一样,例如,它仍在重绘。大致等同于 DoEvents(),尽管没有那么危险。
但它最大的问题是它不允许您的 PutFileAsyncCompleted 事件处理程序运行,底层异步工作程序是一个普通的 BackgroundWorker。它在启动它的同一个线程上触发它的事件,这非常好。但在 UI 线程空闲之前,它无法调用其 RunWorkerCompleted 事件处理程序。这不太好,线程卡在 WaitOne() 调用中。对于您现在正在调试的内容完全相同,您的 GetDirListAsyncCompleted 事件处理程序由于相同的原因无法运行。所以它只是停在那里而无法取得进展。
因此完全消除 _uploadResetEvent,转而依赖您的 UploadFinished() 方法。您可以从 e.Cancelled
属性中查明它是否被取消。只有然后您才启动删除目录的代码。遵循相同的模式,使用相应的 XxxAsyncCompleted 事件来决定下一步做什么。根本不需要 MRE。
关于c# - 为什么使用两个 ManualResetEvents 会导致死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26317823/
我正在尝试实现一个类,该类使用一个简单的缓存来保存从内部服务检索到的数据。我正在使用 ManualResetEvent 来阻止多个线程,这些线程可能会尝试与第一个线程同时刷新缓存数据,以便在通过调用
我有要处理的批处理列表。永远。 我想并行处理每个 block (5),完成后移动到下一个 block 。 出于某种原因,下面的代码不会等待 block 完成并继续,即使它没有完成。 while (tr
我知道如何使用 ManualResetEvent 或同步原语(如 Monitor)来等待事件和/或锁定,但我想知道是否有一种方法可以实现如下内容: ManualResetEvent resetEven
问题: 我正在尝试从 ThreadPool 中抛出 6 个线程来处理单个任务。每个任务的ManualResetEvent 都存储在一个手动重置事件数组中。线程数对应ManualResetEvent数组
我正在使用一个使用 ManualResetEvent 同步线程的应用程序。 FxCop 告诉我处理这些对象。我发现以下讨论告诉我相同的内容: Do I need to Dispose() or Clo
我有一个类允许其他线程等待,直到它使用 ManualResetEventSlim 完成操作。 (操作通常很简短) 这个类没有明确的生命周期,所以没有一个地方可以轻松关闭事件。 相反,我想在事件完成后立
嗨当我使用以下代码时: myManualResetEvent.Dispose(); 编译器报错: 'System.Threading.WaitHandle.Dispose(bool)' is in
假设我必须在 .Net 3.5 SP1 中编排同步算法,标题中列出的任何同步原语都非常适合该任务。 从性能的角度来看,是否有任何一个比其他的性能更好? 我问这个是因为我已经编码了一段时间,但对这个主题
我在锁定 manualResetEvent 实例时遇到了死锁。我无法弄清楚如何解决它。我将不胜感激任何帮助。 我在一个由不同线程执行的类中有两个方法: private ManualResetEvent
我有以下代码 ThreadPool.QueueUserWorkItem(new WaitCallback(DownloadAsync), apiMethod); downloadHandle.Wait
我觉得我应该知道这个问题的答案,但我还是会问,以防万一我犯了一个潜在的灾难性错误。 以下代码按预期执行,没有错误/异常: static void Main(string[] args) { M
我对我的简单代码有疑问: public partial class Form1 : Form { ManualResetEvent ResetEvt = new ManualResetEvent
我写了一个下载一些文件的方法,现在我试图让它并行下载最多 5 个文件,其余的等待前面的文件完成。我为此使用了 ManualResetEvent,但是当我包含同步部分时,它不再下载任何内容(没有它就可以
是c# ManualResetEvent和 AutoResetEvent创建或维护类的成本很高吗? 它们是否消耗某种有限的 Windows 内核资源,如果是,它的限制程度如何? 例如如果我的代码可以每
我还处于计划阶段,所以我没有完整的代码可以展示。但是我很好奇,如果您想在不同的程序集之间同步线程,将如何使用 manualresetevent。例如,我在 assembly1 中编写了执行 task1
我正在使用 Starksoft.Net.Ftp 执行异步上传操作。 看起来像这样: public void UploadFile(string filePath, string package
我有一个 Windows 服务,它使用带有回调的 System.Threading.Timer 来更新端点,如下所示: UpdateEndpointTimer = new Timer(
我正在测试中使用 ManualResetEvent 类。 基本上,我想在调用特定函数时调用 Set() 方法。这看起来像: var mre = new ManualResetEvent(false);
在我的一个项目中,我需要安排一项任务在后台线程中的某个指定时间间隔后完成。我使用 ThreadPool.RegisterWaitForSingleObject 机制来做到这一点。根据文档,第一个参数可
我对我正在使用的 ManualResetEvent 感到有点困惑,它似乎没有解锁。有人知道为什么会这样吗? 我遇到的情况与此类似。实际情况相当复杂,我没有设法隔离出一段可以合理发布以重现问题的代码。
我是一名优秀的程序员,十分优秀!