文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C#中ManualResetEvent实现线程的暂停与恢复

2024-04-02 19:55

关注

背景

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

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

ManualResetEvent介绍

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

实现设计

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

 2.具体交互逻辑如下

默认开启一个线程,并通过WaitOne挂起,等待手动开始自动刷新的指令
手动通过Set方法发送开始工作信号
执行完面操作后,通过Reset将线程再次挂起,并等待Ajax结果,判断Ajax结果,如果不等于AVALIABLE则再次恢复线程

        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请求

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

MyRequestHandler中需要指定自定义ResourceHandler

    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再次恢复线程

    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的重复查询

        public static void StartListenFunc()
        {
            _eventBeginListenWorkList.Set();
            StartListen = true;
        }

ManualResetEvent官方介绍如下

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

到此这篇关于C#中ManualResetEvent实现线程的暂停与恢复的文章就介绍到这了,更多相关C# 线程暂停恢复内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯