应用多线程:解决等待超时问题
作者:天涯 来源:中国自学编程网 发布日期:1221095373
我们日常工作中常会遇到这种场景:数据库、远程webservice、串口设备等等连接失败,或其他需要长时间等待才能返回错误信息的情况。这时我们需要设定一个超时时间如果出现问题能够及时反馈给用户。虽然我们给数据库或webservice把超时设定很短,但这样做不灵活因为有些操作本身就是很耗时的。因此我们应该利用多线程来解决这个问题。
其实这个问题很好解决,会超时的操作用异步执行(异步委托或者线程池),用户主线程进行等待通知(ManualResetEvent)。如果用户在超时时间能都没等到就会激发超时事件通知用户。看代码吧一目了然:
public class TimeoutChecker
{
long _timeout; //超时时间
Action _proc; //会超时的代码
Action _procHandle; //处理超时
Action _timeoutHandle; //超时后处理事件
ManualResetEvent _event = new ManualResetEvent(false);
public TimeoutChecker(Action proc, Action timeoutHandle)
{
this._proc = proc;
this._timeoutHandle = timeoutHandle;
this._procHandle = delegate
{
//计算代码执行的时间
Stopwatch sw = new Stopwatch();
sw.Start();
if (this._proc != null)
this._proc();
sw.Stop();
//如果执行时间小于超时时间则通知用户线程
if (sw.ElapsedMilliseconds < this._timeout && this._event != null)
{
this._event.Set();
}
};
}
public bool Wait(long timeout)
{
this._timeout = timeout;
//异步执行
this._procHandle.BeginInvoke(null, null);
//如果在规定时间内没等到通知则为false
bool flag = this._event.WaitOne((int)timeout, false);
if (!flag)
{
//触发超时时间
if (this._timeoutHandle != null)
this._timeoutHandle();
}
this.Dispose();
return flag;
}
private void Dispose()
{
if(this._event != null)
this._event.Close();
this._event = null;
this._proc = null;
this._procHandle = null;
this._timeoutHandle = null;
}
}
代码很简单,下面是调用例子
TimeoutChecker we = new TimeoutChecker(delegate
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = "server=.;database=test;uid=sa;pwd=s";
conn.Open();
}}, delegate { Console.WriteLine("数据库不存在"); });
if (we.Wait(200))
Console.WriteLine("链接成功");
是不是很方便啊。
作者:天涯 来源:中国自学编程网 发布日期:1221095373
我们日常工作中常会遇到这种场景:数据库、远程webservice、串口设备等等连接失败,或其他需要长时间等待才能返回错误信息的情况。这时我们需要设定一个超时时间如果出现问题能够及时反馈给用户。虽然我们给数据库或webservice把超时设定很短,但这样做不灵活因为有些操作本身就是很耗时的。因此我们应该利用多线程来解决这个问题。
其实这个问题很好解决,会超时的操作用异步执行(异步委托或者线程池),用户主线程进行等待通知(ManualResetEvent)。如果用户在超时时间能都没等到就会激发超时事件通知用户。看代码吧一目了然:
public class TimeoutChecker
{
long _timeout; //超时时间
Action _proc; //会超时的代码
Action _procHandle; //处理超时
Action _timeoutHandle; //超时后处理事件
ManualResetEvent _event = new ManualResetEvent(false);
public TimeoutChecker(Action proc, Action timeoutHandle)
{
this._proc = proc;
this._timeoutHandle = timeoutHandle;
this._procHandle = delegate
{
//计算代码执行的时间
Stopwatch sw = new Stopwatch();
sw.Start();
if (this._proc != null)
this._proc();
sw.Stop();
//如果执行时间小于超时时间则通知用户线程
if (sw.ElapsedMilliseconds < this._timeout && this._event != null)
{
this._event.Set();
}
};
}
public bool Wait(long timeout)
{
this._timeout = timeout;
//异步执行
this._procHandle.BeginInvoke(null, null);
//如果在规定时间内没等到通知则为false
bool flag = this._event.WaitOne((int)timeout, false);
if (!flag)
{
//触发超时时间
if (this._timeoutHandle != null)
this._timeoutHandle();
}
this.Dispose();
return flag;
}
private void Dispose()
{
if(this._event != null)
this._event.Close();
this._event = null;
this._proc = null;
this._procHandle = null;
this._timeoutHandle = null;
}
}
代码很简单,下面是调用例子
TimeoutChecker we = new TimeoutChecker(delegate
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = "server=.;database=test;uid=sa;pwd=s";
conn.Open();
}}, delegate { Console.WriteLine("数据库不存在"); });
if (we.Wait(200))
Console.WriteLine("链接成功");
是不是很方便啊。