其他分享
首页 > 其他分享> > 为方法增加一个超时等待

为方法增加一个超时等待

作者:互联网

为方法增加一个超时等待

FindWindow 查找窗口直接执行可能窗口还没有准备好,返回结果必然是0。通常使用 Thread.Sleep 进行阻塞等待,是一种有效的手段。因计算机CPU运算效率差异,不能保证及时准确的得到想要的结果。所以有必要使用一个保证效率的基础上并可控的方式,下面是我的处理方式,代码使用 C# 编写,其他语言照葫芦画瓢。

TimeoutMonitor.cs

/// <summary>
/// 超时监视器
/// </summary>
public class TimeoutMonitor
{
    readonly int _tickCount;

    /// <summary>
    /// 创建一个超时监视器
    /// </summary>
    /// <param name="timeout">超时时间(毫秒)</param>
    public TimeoutMonitor(int timeout)
    {
        _tickCount = Environment.TickCount;
        Timeout = timeout;
    }

    /// <summary>
    /// 超时时间(毫秒)
    /// </summary>
    public int Timeout { get; }

    /// <summary>
    /// 完成的
    /// </summary>
    public bool IsCompleted => Environment.TickCount - _tickCount > Timeout;

    /// <summary>
    /// 调用超时,如果超时将抛出 TimeoutException 错误
    /// </summary>
    /// <param name="error">错误描述</param>
    public void ThrowIfTimeout(string error) => ThrowIfTimeout(error, 0);

    /// <summary>
    /// 调用超时,如果超时将抛出 TimeoutException 错误
    /// </summary>
    /// <param name="error">错误描述</param>
    /// <param name="sleepTimeout">阻塞间隔(毫秒)</param>
    public void ThrowIfTimeout(string error, int sleepTimeout)
    {
        if (IsCompleted) throw new TimeoutException(error);
        if (sleepTimeout > 0) Thread.Sleep(sleepTimeout);
    }

    /// <summary>
    /// 根据条件调用超时,如果超时将抛出 TimeoutException 错误
    /// </summary>
    /// <param name="func">返回 true 时立即跳出后续</param>
    /// <param name="timeout">超时时间(毫秒)</param>
    /// <param name="error">错误描述</param>
    public static void ThrowIfTimeout(Func<bool> func, int timeout, string error)
    {
        var tickCount = Environment.TickCount;
        while (Environment.TickCount - tickCount < timeout) if (func()) return;
        throw new TimeoutException(error);
    }

    /// <summary>
    /// 等待超时退出
    /// </summary>
    /// <param name="func">返回 true 时立即跳出后续</param>
    /// <param name="timeout">超时时间(毫秒)</param>
    /// <returns>返回 true 未超时,反之 false 超时</returns>
    public static bool WaitTimeout(Func<bool> func, int timeout)
    {
        var tickCount = Environment.TickCount;
        while (Environment.TickCount - tickCount < timeout) if (func()) return true;
        return false;
    }
}

例子

可适用大多数非阻塞的方法:等待文件完全写入、等待窗口关闭……

FindWindowTimeout

在指定时间内一直 FindWindow 如果非 0 立即返回,到达指定时间后返回 0。

[DllImport("user32.dll")]
static extern IntPtr FindWindow(string lpszClass, string lpszWindow);

public static IntPtr FindWindowTimeout(string lpszClass, string lpszWindow, int timeout)
{
    var timeoutMonitor = new TimeoutMonitor(timeout);
    while (!timeoutMonitor.IsCompleted)
    {
        var hWnd = FindWindow(lpszClass, lpszWindow);
        if (hWnd != IntPtr.Zero) return hWnd;
    }
    return IntPtr.Zero;
}

等待文件完全写入

var fi = new FileInfo(@"C:\1.txt");
TimeoutMonitor.ThrowIfTimeout(() => fi.Exists && fi.Length > 0, 15000, "文件不存在");
var s = File.ReadAllText(fi.FullName);

等待窗口关闭

const int WM_CLOSE = 0x0010;

[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

[DllImport("user32.dll")]
static extern bool IsWindow(IntPtr hWnd);

public static bool WaitCloseWindow(IntPtr hWnd, int timeout)
{
    SendMessage(hWnd, WM_CLOSE, 0, 0);
    return TimeoutMonitor.WaitTimeout(() => !IsWindow(hWnd), timeout);
}

标签:string,int,等待,timeout,hWnd,超时,方法,public
来源: https://www.cnblogs.com/dao/p/16608192.html