gpt4 book ai didi

c# - 为什么使用两个 ManualResetEvents 会导致死锁?

转载 作者:太空宇宙 更新时间:2023-11-03 21:27:13 25 4
gpt4 key购买 nike

我正在使用 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com