前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ManualResetEvent实现线程的暂停与恢复

ManualResetEvent实现线程的暂停与恢复

作者头像
Chester Chen
修改2022-08-18 15:15:48
6820
修改2022-08-18 15:15:48
举报
文章被收录于专栏:chester技术分享chester技术分享

背景

前些天遇到一个需求,在没有第三方源码的情况下,刷新一个第三方UI,并且拦截到其ajax请求的返回结果。当结果为AVALIABLE的时候,停止刷新并语音提示,否则继续刷新。

分析这个需求,发现需要控制一个刷新循环的暂停与开始,因此网上搜到了通过ManualResetEvent实现线程的暂停与恢复。

ManualResetEvent介绍

ManualResetEvent是一个通过信号机制,实现线程间状态同步的类。常用的方法有以下三个:

WaitOne:阻止当前线程,直到收到信号

Reset:将事件状态设置为非终止状态,导致线程阻止

Set:将事件状态设置为终止状态,从而允许继续执行一个或多个等待线程

实现设计

1.通过CefSharp的谷歌浏览器插件请求第三方网站

2.具体交互逻辑如下

  1. 默认开启一个线程,并通过WaitOne挂起,等待手动开始自动刷新的指令
  2. 手动通过Set方法发送开始工作信号
  3. 执行完面操作后,通过Reset将线程再次挂起,并等待Ajax结果,判断Ajax结果,如果不等于AVALIABLE则再次恢复线程
代码语言:javascript
复制
public Form1()
{
    InitializeComponent();
    var setting = new CefSettings();
    setting.Locale = "zh-CN";
    setting.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36";
    // 避免页面加载不出来, 建议加上这句
    Cef.Initialize(setting);

    workerThread = new Thread(new ThreadStart(BeginListenWorkerAsync));
    workerThread.IsBackground = true;
    workerThread.Start();

    this.停止自动监听ToolStripMenuItem.Enabled = false;
}

private async void BeginListenWorkerAsync()
{
    while (true)
    {
        _eventBeginListenWorkList.WaitOne();  //1.默认挂起线程,等待信号
        chromiumWebBrowser1.GetBrowser().MainFrame.ExecuteJavaScriptAsync(@"document.evaluate(""//*[@id='root']/div[1]/div[2]/div/div[2]/div[1]/div[1]/div/div[1]/button"", document).iterateNext().click()");

        Thread.Sleep(1000);
        chromiumWebBrowser1.GetBrowser().MainFrame.ExecuteJavaScriptAsync(@"document.evaluate(""//*[@id='root']/div[1]/div[2]/div/div[1]/div/div/div/div[2]/div[6]/div/button"", document).iterateNext().click()");
        _eventBeginListenWorkList.Reset(); //3.页面执行完相应操作则再次挂起线程,等待ajax请求结果再判断是否恢复线程
    }
}

private void 停止自动监听ToolStripMenuItem_Click(object sender, EventArgs e)
{
    this.开始自动监听ToolStripMenuItem.Enabled = true;
    this.停止自动监听ToolStripMenuItem.Enabled = false;
    _eventBeginListenWorkList.Reset();
    StartListen = false;
}

private void 开始自动监听ToolStripMenuItem_Click(object sender, EventArgs e)
{
    this.开始自动监听ToolStripMenuItem.Enabled = false;
    this.停止自动监听ToolStripMenuItem.Enabled = true;
    _eventBeginListenWorkList.Set(); // 2.手动通过Set发送信号恢复线程,让其工作
    StartListen = true;
}

3.现在我们需要定义RequestHandler来指定ResourceHandler拦截ajax请求

代码语言:javascript
复制
private void Form1_Load(object sender, EventArgs e)
{
    chromiumWebBrowser1.RequestHandler = new MyRequestHandler(this);
    chromiumWebBrowser1.Load("https://www.xxxxxxxx.com/");
}

MyRequestHandler中需要指定自定义ResourceHandler

代码语言:javascript
复制
public class MyRequestHandler : RequestHandler
{
    Form1 _form;
    public MyRequestHandler(Form1 form)
    {
        _form = form;
    }
    public static string AuthorizationValue;
    protected override bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture,
        bool isRedirect)
    {
        // 先调用基类的实现,断点调试
        return base.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect);
    }

    protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame,
        IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
    {
        Console.WriteLine(request.Url);
        if (request.Url.StartsWith("https://www.xxxxxxxxxxxxxxxx/api") && request.Headers.AllKeys.Contains("Authorization"))
        {
            AuthorizationValue = request.Headers["Authorization"];
        }

        return new MyResourceRequestHandler(_form);
    }
}

4.最后ResourceRequestHandler拦截到ajax请求之后,如果结果不是AVALIABLE则通过StartListenFunc再次恢复线程

代码语言:javascript
复制
public class MyResourceRequestHandler : ResourceRequestHandler
{
    Form1 _form;
    public MyResourceRequestHandler(Form1 form)
    {
        _form = form;
    }
    private Dictionary<ulong, MemoryStreamResponseFilter> responseDictionary = new Dictionary<ulong, MemoryStreamResponseFilter>();
    protected override IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response)
    {
        var dataFilter = new MemoryStreamResponseFilter();
        responseDictionary.Add(request.Identifier, dataFilter);
        return dataFilter;
    }

    protected override void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength)
    {
        MemoryStreamResponseFilter filter;
        if (responseDictionary.TryGetValue(request.Identifier, out filter))
        {
            var data = filter.Data;
            
            if (request.Url.StartsWith("https://xxxxxxxxxxxxxxxxxxxx/oneapi"))
            {
                var available = false;
                string s = System.Text.Encoding.UTF8.GetString(data, 0, data.Length);
                Console.WriteLine(s);
                if (!string.IsNullOrEmpty(s))
                {
                    var responseData = JsonConvert.DeserializeObject<ScheduleResponse>(s);
                    if (responseData != null && responseData.productPreviews != null)
                    {
                        foreach (var item in responseData.productPreviews)
                        {
                            if (item.schedule != null && item.schedule.status != null && item.schedule.status.name == "AVAILABLE")
                            {
                                available = true;
                                Mp3Player.Play();
                                Action act = delegate () { _form.StopListen(); };
                                _form.Invoke(act);
                                break;
                            }
                        }
                    }
                }

                if (!available && Form1.StartListen)
                {
                    Form1.StartListenFunc();
                }
            }
            
            filter.Dispose();
        }
    }
}

而StartListenFunc则是通过Set方法再次恢复了线程对ui的重复查询

代码语言:javascript
复制
public static void StartListenFunc()
{
    _eventBeginListenWorkList.Set();
    StartListen = true;
}

ManualResetEvent官方介绍如下

https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.manualresetevent?view=netframework-1.1

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 chester技术分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • ManualResetEvent介绍
  • 实现设计
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档