CODE-非同步方法之同步化及逾時機制(完成回Call版)
1 |
前天寫了一篇 非同步方法之同步化及逾時機制,與chicken大人討論程式碼中Polling的部分(指每隔一段時間檢查一次結果的輪詢寫法),固然邏輯簡單,但效率與精確度不優,但若被呼叫的元件本身不提供"完成後主動通知"的機制,Polling雖然討厭,卻也無法避免!
若被呼叫端在完成工作時,可透過事件回呼方式通知呼叫方,則整個局勢就改觀了! 於是索性也提筆敲鍵練習一番,補充"完成後會回Call"情境的做法。
如下例,我們在AsyncJobClass完成工作後,新增主動回Call AfterFinished事件通知呼叫方的功能(橘底部分),如此便可引用AutoResetEvent來做同步。做法是先宣告一個AutoResetEvent,並在AfterFinished事件中呼叫AutoResetEvent.Set()。則DoAsyncJob()後,我們便可使用AutoResetEvent.WaitOne(TimeoutMilliSeconds)等待工作完成觸發AutoResetEvent.Set()並指定逾時上限,整個邏輯頓時簡化許多。
程式碼如下,恭請參考指教。
using System;
using System.Threading;
class Program
{
static AutoResetEvent sync = new AutoResetEvent(false);
static void Main(string[] args)
{
AsyncJobClass.Ready = false;
//set AutoResetEvent after finished
AsyncJobClass.AfterFinished = () =>
{
sync.Set();
};
try
{
AsyncJobClass.Ready = false;
AsyncJobClass.DoAsyncJob(false);
//Test 2, Timeout = 3s
sync.WaitOne(3000);
if (!AsyncJobClass.Ready)
throw new ApplicationException("Timeout!");
}
catch (Exception e)
{
Console.WriteLine("Error=" + e.Message);
Console.WriteLine("Test 2, longer than timeout, OK!");
}
Console.Read();
}
}
class AsyncJobClass
{
public static bool Ready = false;
//Simulating async work
//delay 5 sec, than set Ready = true, or throw an exception in purpose
public static void DoAsyncJob(bool raiseException)
{
ThreadPool.QueueUserWorkItem((o) =>
{
if (raiseException)
OnError(new ApplicationException("Exception in Purpose!"));
else
{
Thread.Sleep(5000);
Ready = true;
AfterFinished();
}
});
}
//The event triggered when exception raised
public static Action<Exception> OnError;
//The event triggered after finished
public static Action AfterFinished;
}
【補充參考】
Comments
# by laneser
事實上我都這麼寫的: static void Main(string[] args) { Thread t = new Thread(() => { Thread.Sleep(5000); Console.WriteLine("done!"); }); t.Start(); bool IsDone = t.Join(3000); Console.WriteLine("test is longer than timeout"); Console.Read(); }