ManualResetEvent实现线程的暂停与恢复

背景

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

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

ManualResetEvent介绍

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

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

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

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

实现设计

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

41aaa78520e708e1af3049f352e112aa.png

 2.具体交互逻辑如下

  1. 默认开启一个线程,并通过WaitOne挂起,等待手动开始自动刷新的指令

  2. 手动通过Set方法发送开始工作信号

  3. 执行完面操作后,通过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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java反射异常之java.lang.NoSuchFieldException: school

今天调用下面的代码的时候 Field schoolField studentClass.getField("school");schoolField.setAccessible(true);schoolField.set(null, "中南林科大");System.out.print("school:" student.getSchool()); 爆出java.lang.NoSuchFieldExcept…

浙大哈佛剑桥学者联手破解数学界几十年的谜题,成果登上数学顶刊

全世界只有3.14 % 的人关注了爆炸吧知识转自&#xff1a;量子位作者&#xff1a;边策 萧箫当两个看似“无关”的数学领域发生碰撞&#xff0c;会发生什么&#xff1f;浙江大学研究员、中科大数学系2003级校友叶和溪&#xff0c;与来自剑桥大学、哈佛大学的两位学者一起&#xf…

pythontemp_python 临时文件夹 的 tempfile模块学习

python的临时文件夹的tempfile模块学习应用程序经常要保存一些临时的信息&#xff0c;这些信息不是特别重要&#xff0c;没有必要写在配置文件 里&#xff0c;但又不能没有&#xff0c;这时候就可以把这些信息写到临时文件里。其实很 多程序在运行的时候&#xff0c;都会产生一…

Hibernate 参数设置一览表

Hibernate 参数设置一览表属性名用途hibernate.dialect一个Hibernate Dialect类名允许Hibernate针对特定的关系数据库生成优化的SQL. 取值 full.classname.of.Dialect hibernate.show_sql输出所有SQL语句到控制台. 有一个另外的选择是把org.hibernate.SQL这个log category设为d…

jsp将鼠标放到那显示信息

将下面的代码&#xff0c;粘贴复制到jsp<body></body>中<A href"#" οnmοuseοver"document.getElementById(aaa).style.display" οnmοuseοut"document.getElementById(aaa).style.displaynone">鼠标移动到这我就出来了&l…

Monkey测试实例

Monkey是Android中的一个命令行工具&#xff0c;可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等)&#xff0c;实现对正在开发的应用程序进行压力测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。1…

.NET Core Runtime vs .NET Framework Runtime

在我从 .NET Framework 到 .NET Core 的过渡期间&#xff0c;有一件事情让我很长时间都感到困惑&#xff0c;那就是 Runtime 运行时&#xff0c; 实际上 Runtime 在 .NET Framework 和 .NET Core 中具有不同的含义。.NET Framework 运行时的历史 当有人问我们&#xff0c;什么是…

linux下ctrl 常用组合键

Ctrlc 结束正在运行的程序 Ctrld 结束输入或退出shell Ctrls 暂停屏幕输出【锁住终端】 Ctrlq 恢复屏幕输出【解锁终端】 Ctrll 清屏&#xff0c;【是字母L的小写】等同于Clear Ctrla 切换到命令行开始 Ctrle 切换到命令行末尾 Ctrlu 清除剪切光标之前的内容 Ctrlk 清除剪切光标…

“玻璃大王”曹德旺捐资100亿办大学!幼年失学的他要打造理工科研究型大学...

全世界只有3.14 % 的人关注了爆炸吧知识本文转自募格学术整理自&#xff1a;量子位&#xff08;作者贾浩楠、鱼羊&#xff09;、青塔等100亿投资&#xff0c;福建省迎来第一个“新型大学”。办学资金&#xff0c;来自生长于福建&#xff0c;在福建发家致富的“玻璃大王”曹德旺…

python进程join的用法_python 进程介绍 进程简单使用 join 验证空间隔离

一、多道程序设计技术(详情参考&#xff1a;https://www.cnblogs.com/clschao/articles/9613464.html)所谓多道程序设计技术&#xff0c;就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存&#xff0c;并允许它们交替在CPU中运行&#xff0c;它们共享系统中的各…

北京易维清的自荐

北京易维清是什么东西呢&#xff0c;是一家以asp.net、winform、MVC源代码生成器为主打产品&#xff0c;同时兼顾信息管理系统项目开发的信息技术公司&#xff0c;更多信息可以访问www.evkchina.com 不过这里不是北京易维清的广告也不是产品说明书&#xff0c;广告什么的都是浮…

PHP的学习--PHP的闭包

php的闭包&#xff08;Closure&#xff09;也就是匿名函数&#xff0c;是PHP5.3引入的。 闭包的语法很简单&#xff0c;需要注意的关键字就只有use&#xff0c;use是连接闭包和外界变量。 $a function() use($b) {} 简单例子如下&#xff1a; function callback($fun) { $fun(…

JAVA配置Tomcat

1.下载tomcat&#xff0c;我jdk是1.8的&#xff0c;网上查了一下&#xff0c;说要安装tomcat8及以上的tomcat 尝试点击&#xff0c;弹出&#xff0c; 2.配置环境 3.安装通过cmd安装 4.点击开启服务 5.输入localhost:8080查看 6.还可以通过tomcat8w.exe来启动窗口&#xff0c;开…

如何使用 C# 判断一个文件是否为程序集

程序集是经由编译器编译得到的&#xff0c;供 CLR 进一步编译执行的那个中间产物。它一般表现为 .dll 或者是 .exe 的格式&#xff0c;但是要注意&#xff0c;它们跟普通意义上的 WIN32 可执行程序是完全不同的东西&#xff0c;程序集必须依靠 CLR 才能顺利执行。程序集是 .NET…

Android之手机文件夹目录详解

android系统的手机文件夹目录详解一、文件夹1./acct/系统回收站&#xff0c;删除的系统文件。2./cache/缓存3./data/用户的所有程序相关数据app/所有用户安装的apk文件app-private/data/每一个应用的数据com.xx.appname/每一个应用的数据都存放在本目录下的一个以包名为命名的文…

女孩看男孩VS男孩看女孩

1 这波猫粮我吃了&#xff01;2 论一只狗子的自娱自乐精神&#xff01;3 分享一个 “想死你了”的拥抱&#xff01;4 老师&#xff1a;下课铃不代表这节课上完了5 谁怕谁啊&#xff01;6 好像很有道理的样子7 将它们展开会是什么&#xff1f;你点的每个赞&#xff0c;我都认真当…

利用js对table动态增加和删除行(附带table样式,鼠标滑过和点击样式)

看了一下午各种大牛关于js动态画表的文章&#xff0c;自己也手痒写了一个。附带了一些table的样式&#xff0c;鼠标滑过和选择的样式。有用的拿去参考&#xff0c;有意见和想法的也随时欢饮交流&#xff0c;本人只是用firefox和IE11测试可用。下面是htm代码&#xff1a;<bod…

Struts 2.x No result defined for action 异常

这是我跑struts2的第一个例子&#xff0c;跑的也够郁闷的&#xff0c;这个问题烦了我几个钟。。。 2011-5-10 10:10:17 com.opensymphony.xwork2.util.logging.commons.CommonsLogger warn警告: Could not find action or resultNo result defined for action com.augur.action…

python 文件写入多个参数_pandas 把数据写入txt文件每行固定写入一定数量的值方法...

我遇到的情况是&#xff1a;把数据按一定的时间段提出。比如提出每天6:00-8:00的每个数据&#xff0c;可以这样做&#xff1a;# -*-coding: utf-8 -*-import pandas as pdimport datetime#读取csv文件dfpd.read_csv(A_220DoWVC.csv)#求ave_time这一列的平均值aveTimedf[ave_tim…

使用建造者模式创建模拟数据

前言在写测试用例时&#xff0c;我们经常需要创建模拟数据&#xff0c;在C#中常用的方式是使用nuget包Bogus。Bogus可以按照一定规则生成随机数据&#xff0c;示例代码如下&#xff1a;public class User {public string Name { get; set; }public int Age { get; set; }public…