在 .NET 裡要執行外部程式我們都是用 System.Diagnostics.Process.Start 方法,不過我們在執行外部程式時經常會需要設定 Timeout 逾時時間,以確保原本的主程式能夠繼續運作下去。除此之外,我今天也會介紹「同步」與「非同步」的 Timeout 撰寫技巧。
使用 System.Diagnostics.Process.Start 方法執行一個外部程式非常容易,最簡單的範例如下:
以上這行程式是執行下去後就不管了,因為 .NET 預設是以「非同步」的方式執行外部程式,所以這行程式執行完後不會等待外部程式執行完畢,原本的主程式會繼續往下執行。如果你要等待外部程式執行完畢再繼續的話,可以用以下技巧:
Process p = Process.Start("calc");
// 無窮無盡的等待 calc (小算盤) 執行結束會才會繼續執行
p.WaitForExit();
如果你需要限制外部程式最多執行 60 秒的話,可以參考以下程式。但請注意最後一行的 p.Kill(); 程式,如果沒有執行這行程式的話,原本被啟動的程式還是會繼續執行喔。
Process p = Process.Start("calc");
// 等待 calc (小算盤) 執行,若執行超過 60 秒會回傳 False
if (!p.WaitForExit(1000 * 60))
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("程式執行超過 60 秒,請按任意鍵強制結束執行中的程式...");
Console.ReadKey();
// 將程式強制關閉
p.Kill();
}
以上提到的都是屬於「同步式」程式執行等待與結束的方式,Process 類別還有提供 Process.Exited 事件可以在「非同步」的執行環境下 ( 例如 WinForm ) 靈活運用,讓你可以在程式結束時委派一個方法(method) 執行相關程式或傳送訊息。以下是個比 MSDN 範例程式還簡單的範例,比較特別的地方是 EnableRaisingEvents 屬性必須設定為 true 才會觸發事件,此屬性預設為 false。
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
// 用來判斷程式是否結束
static bool m_IsTerminated = false;
static void Main(string[] args)
{
Process p = Process.Start("calc");
p.EnableRaisingEvents = true;
p.Exited += delegate { m_IsTerminated = true; };
while (!m_IsTerminated)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(".");
Thread.Sleep(1000);
}
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("程式已結束");
}
}
}
最後,如果你想要用「非同步」的方式等待指定的時間讓程式超過執行時間自動關閉的話,可以利用之前提過的 ThreadPool 類別進行撰寫,讓程式可以在一個獨立的 Thread 中執行,並且在該 Thread 中等待程式執行完畢。
using System;
using System.Diagnostics;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
// 用來判斷程式是否結束
static bool m_IsTerminated = false;
static void Main(string[] args)
{
// 透過 ThreadPool 讓程式獨立的 Thread 中執行
ThreadPool.QueueUserWorkItem(delegate
{
Process p = Process.Start("calc");
if (!p.WaitForExit(1000 * 60))
{
p.Kill();
m_IsTerminated = true;
}
});
while (!m_IsTerminated)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write(".");
Thread.Sleep(1000);
}
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("程式已結束");
}
}
}
其他有關 Process 類別的說明請參考 MSDN 文件說明。