我有一个服务在循环中运行一些不同的任务,直到服务停止。
但是,我调用Web服务和此调用的其中一个任务可能需要几分钟才能完成。我希望能够立即停止服务,“取消”Web服务调用而不调用Thread.Abort
因为这会导致一些奇怪的行为,即使线程正在做的唯一事情是调用此Web服务方法。
如何取消或中断同步方法调用(如果可能的话)? 或者我应该尝试不同的方法?
我尝试使用AutoResetEvent
,然后调用Thread.Abort
,这在以下代码示例中工作正常,但在实际服务中实现此解决方案时,我得到一些意外行为可能是因为什么是继续我正在使用的外部库。
AutoResetEvent
和Thread.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 :(得分: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
答案 1 :(得分:2)
解决方案真的很简单:除非你想要阻止几分钟,否则不要拨打几分钟的电话。如果在没有阻塞的情况下无法做任何特定事情,可能持续几分钟,就会大声抱怨那些编写强制要求的代码(或者如果可能的话自己修复)。
一旦你打完电话,就太晚了。你承诺了。如果您调用的函数没有提供中止它的安全方法,那么就没有安全的方法了。
答案 2 :(得分:0)
因为您要做的就是一次做一个异步Web服务调用,并且在每个响应进行另一个调用时,您可以省去工作线程并简单地进行异步调用,注册回调并从另一个异步调用回调:
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。