2011-12-01 71 views
6

我已經/停止,在它自己的線程中運行,並且可以啓動的進程不會阻塞。這將最終進入Windows服務,但我現在將它設置在控制檯應用程序中,直到完全充實爲止。使用信號量而不是while循環。這是好還是壞?

後調用start()方法,我想主程序線程阻塞,直到按Ctrl-C。我知道這將工作:

public static void Main(string[] args) 
{ 
    bool keepGoing = true; 

    var service = new Service(); 

    System.Console.TreatControlCAsInput = false; 

    System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) 
    { 
     e.Cancel = true; 
     service.Stop(); 
     keepGoing = false; // Break the while loop below 
    }; 

    service.Start(); 

    while(keepGoing) 
    { 
     Thread.Sleep(100); // 100 is arbitrary 
    } 

} 

但是,我覺得標誌和任意睡眠值麻煩。我知道,CPU的成本是在while循環實際上是0,但我寧願有一個「硬」塊只要按Ctrl-C處理程序完成後釋放。我設計了下面的內容,使用信號量來阻止,直到匿名Ctrl-C處理程序完成:

public static void Main(string[] args) 
{ 
    var service = new Service(); 

    var s = new Semaphore(1, 1); 

    System.Console.TreatControlCAsInput = false; 

    System.Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) 
    { 
     e.Cancel = true; 
     service.Stop(); 
     s.Release(); // This will allow the program to conclude below 
    }; 

    service.Start(); 

    s.WaitOne(); // This will not block 
    s.WaitOne(); // This will block w/o CPU usage until the sempahore is released 

} 

這是不好的設計?這是否過分矯枉過正?危險嗎?

編輯:

我也掛鉤AppDomain.CurrentDomain.UnhandledException如下:

AppDomain.CurrentDomain.UnhandledException += delegate { 
    service.Stop(); 
    s.Release(); 
}; 

編輯第二:

我要指出,這是關鍵在退出時調用方法Stop()。 @Adam拉爾夫對混合控制檯/服務一個非常好的模式,但回答Q.

+1

如果你能避免while循環我說,這是值得追求的。 – ChaosPandion

+1

對於後者的原型設計有很大的改進。在生產應用程序中,我會避​​免整個「CTRL + C」突破想法。改用信號來殺死線程。信號是「Set()」的方式取決於涉及的其他層。在設計服務時請記住這一點。添加一個方法,就像可以調用的方法一樣,調用'Set()'。 –

+0

@ P.Brian。Mackey:雖然這不是一個生產應用程序,但如果它*是*,在非交互式控制檯應用程序中,至少要優雅地處理Ctrl-C是否審慎?事實上,Ctrl-C只會關閉程序而沒有機會在退出之前進行清理。最終,我只是想知道信號量解決方案的「while(標誌)Thread.Sleep(...)」選項。 –

回答

4

當沒有這個信息,我們有我們的一些應用程序的類似要求。他們是Windows服務,但爲了調試,我們經常希望將它們作爲控制檯應用程序運行。此外,我們通常編寫新的應用程序作爲Windows服務相當早,但往往不希望有實際運行它們作爲一種服務,直到後來,當我們已經證明了概念等

這是我們模式用途: -

using (var service = new Service()) 
{ 
    if (Environment.UserInterActive) 
    { 
     service.Start(); 
     Thread.Sleep(Timeout.Infinite); 
    } 
    else 
    { 
     ServiceBase.Run(service); 
    } 
} 

告訴線程無限睡覺似乎效率不高,但是這僅僅是用於調試方案和冗餘線程不消耗CPU時間,只是一些內存(約1MB),這主要是由的分配給線程的堆棧空間。該進程仍然可以通過Ctrl + C或通過關閉命令窗口退出。

- 編輯 -

如果發現service.Dispose()當按下Ctrl + C鍵不會被調用(即粗魯中止發生),並調用Dispose()是至關重要的,那麼我想你可以明確地做這像這樣: -

using (var service = new Service()) 
{ 
    if (Environment.UserInterActive) 
    { 
     Console.CancelKeyPress += (sender, e) => service.Dispose(); 
     service.Start(); 
     Thread.Sleep(Timeout.Infinite); 
    } 
    else 
    { 
     ServiceBase.Run(service); 
    } 
} 

注意Stop()Dispose()封裝。

+0

這是否仍然存在這樣的問題:在UserInterActive上下文中,如果用戶試圖停止該進程(使用Ctrl-C或窗口關閉),則不會調用Stop()方法?這是我在上面的示例中試圖完成的。 –

+0

在我們的服務中,調用Stop方法並不重要,但我想您仍然可以訂閱CancelKeyPress並明確地執行此操作。我會編輯答案 –

+0

我在Q中對此不清楚;對不起。我編輯提到這一點。 –