Асинхронный процесс начнется и дождитесь его завершения
Я новичок в модели потоков в .net. Что бы вы использовали для:
- запустите процесс, обрабатывающий файл (process.StartInfo.FileName = имя_файла;)
- дождитесь, когда пользователь закроет процесс ИЛИ отменит поток через некоторое время
- если пользователь закрыл процесс, удалите файл
Запуск процесса и ожидание должны выполняться в другом потоке, кроме основного потока, потому что эта операция не должна влиять на приложение.
Пример:
Мое приложение создает html-отчет. Пользователь может щелкнуть правой кнопкой мыши и сказать "Просмотреть отчет" - теперь я извлекаю содержимое отчета во временный файл и запускаю процесс, который обрабатывает html файлы, то есть браузер по умолчанию. Проблема в том, что я не могу очистить, т.е. Удалить временный файл.
Ответы
Ответ 1
", и ожидание должно быть асинхронным" - я не пытаюсь быть смешным, но разве это не противоречие? Однако, поскольку вы запускаете Process
, событие Exited
может помочь:
ProcessStartInfo startInfo = null;
Process process = Process.Start(startInfo);
process.EnableRaisingEvents = true;
process.Exited += delegate {/* clean up*/};
Если вы хотите действительно подождать (время ожидания и т.д.), то:
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout (perhaps process.Kill();)
}
Для ожидания async, возможно, просто используйте другой поток?
ThreadPool.QueueUserWorkItem(delegate {
Process process = Process.Start(startInfo);
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout
}
});
Ответ 2
Добавление расширенной альтернативы этому старому вопросу. Если вы хотите дождаться завершения процесса без блокировки любого потока и по-прежнему поддерживать таймауты, попробуйте следующее:
public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
{
ManualResetEvent processWaitObject = new ManualResetEvent(false);
processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredProcessWaitHandle = null;
registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
processWaitObject,
delegate(object state, bool timedOut)
{
if (!timedOut)
{
registeredProcessWaitHandle.Unregister(null);
}
processWaitObject.Dispose();
tcs.SetResult(!timedOut);
},
null /* state */,
timeout,
true /* executeOnlyOnce */);
return tcs.Task;
}
Опять же, преимущество этого подхода по сравнению с принятым ответом заключается в том, что вы не блокируете какие-либо потоки, что снижает накладные расходы вашего приложения.
Ответ 3
Попробуйте использовать следующий код.
public void KickOffProcess(string filePath) {
var proc = Process.Start(filePath);
ThreadPool.QueueUserWorkItem(new WaitCallBack(WaitForProc), proc);
}
private void WaitForProc(object obj) {
var proc = (Process)obj;
proc.WaitForExit();
// Do the file deletion here
}
Ответ 4
Я бы, вероятно, не использовал отдельный процесс для открытия файла. Вместо этого я бы использовал фоновый поток (если бы я думал, что операция займет много времени и возможно заблокирует поток пользовательского интерфейса).
private delegate void FileOpenDelegate(string filename);
public void OpenFile(string filename)
{
FileOpenDelegate fileOpenDelegate = OpenFileAsync;
AsyncCallback callback = AsyncCompleteMethod;
fileOpenDelegate.BeginInvoke(filename, callback, state);
}
private void OpenFileAsync(string filename)
{
// file opening code here, and then do whatever with the file
}
Конечно, это не очень хороший рабочий пример (он ничего не возвращает), и я не показывал, как обновляется пользовательский интерфейс (вы должны использовать BeginInvoke на уровне пользовательского интерфейса, потому что фоновый поток не может обновить поток пользовательского интерфейса). Но этот подход, как правило, относится к обработке асинхронных операций в .NET.
Ответ 5
Вы можете использовать событие Exited
в классе Process
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "notepad.exe";
Process process = Process.Start(info);
process.Exited += new EventHandler(process_Exited);
Console.Read();
и в этом случае вы можете обработать упомянутые вами операции