2012-02-14 42 views
2

我有一個服務在循環中運行一些不同的任務,直到服務停止。 然而,我打電話給網絡服務和這個電話的任務之一可能需要幾分鐘才能完成。我希望能夠立即停止服務,'取消'Web服務調用,而不會調用Thread.Abort,因爲這會導致一些奇怪的行爲,即使線程唯一正在調用此Web服務方法。如何在線程正在工作時停止服務(不使用Thread.Abort)

如何取消或從同步方法調用中斷(如果它甚至可能)? 或者我應該嘗試一種不同的方法?

我曾嘗試使用AutoResetEvent,然後調用Thread.Abort這是工作的罰款下面的代碼示例中,但落實在實際的服務這一解決方案時,我得到一些意外的行爲可能是因爲在外部庫發生了什麼事情的我正在使用。

AutoResetEventThread.Abort

class Program 
{ 
    static void Main(string[] args) 
    { 
     MainProgram p = new MainProgram(); 
     p.Start(); 
     var key = Console.ReadKey(); 
     if (key.Key == ConsoleKey.Q) 
      p.Stop(); 
    } 
} 

class MainProgram 
{ 
    private Thread workerThread; 
    private Thread webServiceCallerThread; 
    private volatile bool doWork; 

    public void Start() 
    { 
     workerThread = new Thread(() => DoWork()); 
     doWork = true; 
     workerThread.Start(); 
    } 

    public void Stop() 
    { 
     doWork = false; 
     webServiceCallerThread.Abort(); 
    } 

    private void DoWork() 
    { 
     try 
     { 
      while (doWork) 
      { 
       AutoResetEvent are = new AutoResetEvent(false); 
       WebServiceCaller caller = new WebServiceCaller(are); 
       webServiceCallerThread = new Thread(() => caller.TimeConsumingMethod()); 
       webServiceCallerThread.Start(); 

       // Wait for the WebServiceCaller.TimeConsumingMethod to finish 
       WaitHandle.WaitAll(new[] { are }); 

       // If doWork has been signalled to stop 
       if (!doWork) 
        break; 

       // All good - continue 
       Console.WriteLine(caller.Result); 
      } 
     } 
     catch (Exception e) 
     { 
      Console.Write(e); 
     } 
    } 
} 

class WebServiceCaller 
{ 
    private AutoResetEvent ev; 
    private int result; 

    public int Result 
    { 
     get { return result; } 
    } 

    public WebServiceCaller(AutoResetEvent ev) 
    { 
     this.ev = ev; 
    } 

    public void TimeConsumingMethod() 
    { 
     try 
     { 
      // Simulates a method running for 1 minute 
      Thread.Sleep(60000); 
      result = 1; 
      ev.Set(); 
     } 
     catch (ThreadAbortException e) 
     { 
      ev.Set(); 
      result = -1; 
      Console.WriteLine(e); 
     } 
    } 
} 

有人能提出一個解決這個問題?

+0

不知道你的外部庫在做什麼答案都是純粹的猜測......你理論上可以用一些「標誌」來工作,你可以在這個線程中檢查這個線程是否可以安全地「中止」。 – Yahia 2012-02-14 08:04:21

+0

你可以編寫你的WebServiceCaller和線程機制,以便它可以孤立並在它返回時自己死掉?清除doWork標誌,停止等待線程/事件,將任何回調設置爲null,忘記它,繼續。當長Web服務調用最終返回並且線程將其ref設置爲null並終止它自己時,沒有人注意或關心,(sob ..)。 – 2012-02-14 08:18:14

+0

我可以,但是直到WS調用返回時,我的服務(以及它的進程)纔會完全停止。 – 2012-02-14 08:20:01

回答

2

解決方案非常簡單:除非您想阻止幾分鐘,否則請勿阻止幾分鐘的呼叫。如果沒有辦法沒有阻礙地做某件事情,可能會持續幾分鐘,那麼大聲抱怨編寫代碼的人會施加痛苦的要求(如果可能的話,自己修復它)。

一旦你打了電話,它爲時已晚。你承諾。如果你所調用的函數沒有提供一個安全的方法來中止它,那麼就沒有安全的方法。

+0

你可以在一個完全獨立的線程中執行阻塞調用,如果你需要停止線程,就殺死那個線程。 – CodingBarfield 2012-02-14 08:10:57

+1

@CodingBarfield你怎麼知道這是安全的?如果您在該線程處於關閉狀態時終止該線程(如正在寫入當前處於不一致狀態的文件)需要關閉以徹底關閉該線程,該怎麼辦? – 2012-02-14 08:11:59

+0

那麼,如果真的沒有其他解決方法,那麼也許我應該考慮解決這個問題的另一種方法。 – 2012-02-14 08:12:45

5

嘗試此

public void Start() 
{ 
    workerThread = new Thread(() => DoWork()); 
    doWork = true; 
    workerThread.IsBackground = true; 
    workerThread.Start(); 
} 

線程可以是一個背景線程或前臺線程。 後臺線程與前臺線程相同,但 後臺線程不會阻止進程終止。一旦所有屬於進程的前臺線程都終止,公共的 語言運行時就會結束進程。任何剩餘的後臺線程 已停止並且未完成。

欲瞭解更多詳情,請參閱http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx

+0

爲什麼我在搜索時沒有找到這個。這絕對聽起來像是一個解決方案。我會試試這個,並返回結果。 – 2012-02-14 08:27:41

+0

+1我從來沒有考慮過 - 我認爲服務中的任何線程都將被設置爲後臺線程。 – 2012-02-14 08:30:09

+0

+1 @MartinJames我也認爲它會在後臺運行。然而,我要去的解決方案是異步運行。 – 2012-02-14 11:12:13

0

因爲所有你想要做的就是一個在時間和每個響應撥打另一個電話,你可以用工作線程分配,簡單地做出一個asynchonrous Web服務調用aynchronous呼叫,註冊一個回調和從回調進行另一個異步調用:

class Program 
{ 
    private static WebServiceCaller.TCMDelegate _wscDelegate; 
    private static readonly WebServiceCaller _wsCaller = new WebServiceCaller(); 

    static void Main(string[] args) 
    { 
     _wscDelegate = _wsCaller.TimeConsumingMethod; 

     MakeWSCallAsync(); 

     Console.WriteLine("Enter Q to quit"); 
     while (Console.ReadLine().ToUpper().Trim()!="Q"){} 
    } 

    public static void MakeWSCallAsync() 
    { 
     _wscDelegate.BeginInvoke(OnWSCallComplete, null); 
    } 

    public static void OnWSCallComplete(IAsyncResult ar) 
    { 
     Console.WriteLine("Result {0}", _wscDelegate.EndInvoke(ar)); 

     MakeWSCallAsync(); 
    } 
} 

class WebServiceCaller 
{ 
    public delegate int TCMDelegate(); 

    public int TimeConsumingMethod() 
    { 
     try 
     { 
      // Simulates a method running for 1 minute 
      Thread.Sleep(1000); 
      return 1; 
     } 
     catch (ThreadAbortException e) 
     { 
      return -1; 
     } 
    } 
} 

無阻擋(以及,控制檯線程被阻塞上的ReadLine())和沒有窗戶內核模式同步對象(的AutoResetEvent),其是expensive