在Windows窗体窗口中,多个事件可以触发异步方法。此方法下载文件并对其进行缓存。我的问题是我希望该方法执行一次。换句话说,我想阻止多次下载文件。
如果下载文件的方法被触发两次,我希望第二次调用等待文件(或等待第一种方法完成)。
有人知道如何实现这个目标吗?
更新:我只是想阻止不必要的下载。在我的情况下,当客户端将鼠标放在ListBox中的项目上超过几毫秒时,我们开始下载。我们假设用户将单击并请求该文件。可能发生的是用户将鼠标放在项目上一秒钟,然后单击。在这种情况下,开始下载两次。我正在寻找处理这种情况的最佳方法。
更新2::用户可能会将鼠标移到多个项目上。结果,将发生多次下载。我对这种情况并不是很苛刻,但是现在如果我们面对这种情况,我们不会放弃下载。该文件将被下载(文件通常约为50-100kb),然后将被缓存。
答案 0 :(得分:6)
保持表单变量中发生的事件的状态,让异步方法在执行任何操作之前检查该状态。但请确保您同步对它的访问权限!互斥体和信号量对这种事物有好处。
如果您可以同时下载不同的文件,则需要跟踪列表中的内容以供参考。
如果一次只能下载一个文件,并且您不想排队,那么您也可以在下载某些内容时取消该事件,并在下载完成后将其重新挂起。
答案 1 :(得分:2)
这是一个支持多个文件下载的虚拟实现:
Dictionary<string, object> downloadLocks = new Dictionary<string, object>();
void DownloadFile(string localFile, string url)
{
object fileLock;
lock (downloadLocks)
{
if (!downloadLocks.TryGetValue(url, out fileLock))
{
fileLock = new object();
downloadLocks[url] = fileLock;
}
}
lock (fileLock)
{
// check if file is already downloaded
// if not then download file
}
}
答案 2 :(得分:0)
您可以简单地将方法调用包装在像这样的
这样的锁定语句中private static readonly Object padLock = new Object();
...
lock(padLock)
{
YourMethod();
}
答案 3 :(得分:0)
我不确定如何在C#中完成它,但是在java中,你会在下载文件之前同步类中的私有静态final对象。这将阻止任何进一步的请求,直到当前的请求完成。然后,您可以检查文件是否已下载并采取相应措施。
private static final Object lock = new Object();
private File theFile;
public method() {
synchronized(lock) {
if(theFile != null) {
//download the file
}
}
}
答案 4 :(得分:0)
一般情况下,我同意Michael,在实际获取文件的代码周围使用lock
。但是,如果始终首先发生单个事件,并且您始终可以加载该文件,请考虑使用Futures。在最初的事件中,开始未来的运行
Future<String> file = InThe.Future<String>(delegate { return LoadFile(); });
在所有其他事件中,等待未来的价值
DoSomethingWith(file.Value);
答案 5 :(得分:0)
如果您希望一个线程等待另一个线程完成任务,您可能希望使用ManualResetEvent。也许是这样的:
private ManualResetEvent downloadCompleted = new ManualResetEvent();
private bool downloadStarted = false;
public void Download()
{
bool doTheDownload = false;
lock(downloadCompleted)
{
if (!downloadStarted)
{
downloadCompleted.Reset();
downloadStarted = true;
doTheDownload = true;
}
}
if (doTheDownload)
{
// Code to do the download
lock(downloadCompleted)
{
downloadStarted = false;
}
// When finished notify anyone waiting.
downloadCompleted.Set();
}
else
{
// Wait until it is done...
downloadCompleted.WaitOne();
}
}