C#timer怎么timer是多线程吗处理

首先简单介绍一下timer,这里所说的timer是指的System.Timers.timer,顾名思义,就是可以在指定的间隔是引发事件。官方介绍在这里,摘抄如下:
Timer 组件是基于服务器的计时器,它使您能够指定在应用程序中引发 Elapsed 事件的周期性间隔。然后可通过处理这个事件来提供常规处理。 例如,假设您有一台关键性服务器,必须每周 7 天、每天 24 小时都保持运行。 可以创建一个使用 Timer 的服务,以定期检查服务器并确保系统开启并在运行。 如果系统不响应,则该服务可以尝试重新启动服务器或通知管理员。
&&&&基于服务器的 Timer 是为在多线程环境中用于辅助线程而设计的。 服务器计时器可以在线程间移动来处理引发的 Elapsed 事件,这样就可以比 Windows 计时器更精确地按时引发事件。
如果想了解跟其他的timer有啥区别,可以看这里,里面有详细的介绍,不再多说了(其实我也不知道还有这么多)。那使用这个计时器有啥好处呢?主要因为它是通过.NET Thread Pool实现的、轻量、计时精确、对应用程序及消息没有特别的要求。
下面就简单介绍一下,这个Timer是怎么使用的,其实很简单,我就采用微软提供的示例来进行测试,直接上代码了:
&private static System.Timers.Timer aT
&public static void Main()
&&&&&aTimer = new System.Timers.Timer(10000);
&&&&&aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
&&&&&aTimer.Interval = 2000;
&&&&&aTimer.AutoReset = true;
&&&&&aTimer.Enabled = true;
&&&&&Console.WriteLine("按任意键退出程序。");
&&&&&Console.ReadLine();
&private static void OnTimedEvent(object source, ElapsedEventArgs e)
&&&&&Console.WriteLine("触发的事件发生在: {0}", e.SignalTime);
运行的结果如下,计时蛮准确的:
★重入问题重现及分析
什么叫重入呢?这是一个有关多线程编程的概念:程序中,多个线程同时运行时,就可能发生同一个方法被多个进程同时调用的情况。当这个方法中存在一些非线程安全的代码时,方法重入会导致数据不一致的情况。Timer方法重入是指使用多线程计时器,一个Timer处理还没有完成,到了时间,另一Timer还会继续进入该方法进行处理。下面演示一下重入问题的产生(可能重现的不是很好,不过也能简单一下说明问题了):
private static int outPut = 1;
private static int num = 0;
private static System.Timers.Timer timer = new System.Timers.Timer();
public static void Main()
&&&&timer.Interval = 1000;
&&&&timer.Elapsed += TimersTimerH
&&&&timer.Start();
&&&&Console.WriteLine("按任意键退出程序。");
&&&&Console.ReadLine();
/// &summary&
/// System.Timers.Timer的回调方法
/// &/summary&
/// &param name="sender"&&/param&
/// &param name="args"&&/param&
private static void TimersTimerHandler(object sender, EventArgs args)
&&&&int t = ++
&&&&Console.WriteLine(string.Format("线程{0}输出:{1},&&&&&& 输出时间:{2}", t, outPut.ToString(),DateTime.Now));
&&&&System.Threading.Thread.Sleep(2000);
&&&&outPut++;
&&&&Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(),DateTime.Now));
下面显示一下输出结果:
是不是感觉上面输出结果很奇怪,首先是线程1输出为1,没有问题,然后隔了2秒后线程1自增1后输出为2,这就有问题了,中间为什么还出现了线程2的输出?更奇怪的是线程2刚开始输出为1,自增1后尽然变成了3!其实这就是重入所导致的问题。别急,咱们分析一下就知道其中的缘由了。
首先timer启动计时后,开启一个线程1执行方法,当线程1第一次输出之后,这时线程1休眠了2秒,此时timer并没有闲着,因为设置的计时间隔为1秒,当在线程1休眠了1秒后,timer又开启了线程2执行方法,线程2才不管线程1是执行中还是休眠状态,所以此时线程2的输出也为1,因为线程1还在休眠状态,并没有自增。然后又隔了1秒,这时发生同时发生两个事件,线程1过了休眠状态自增输出为2,timer同时又开启一个线程3,线程3输出的为线程1自增后的值2,又过了1秒,线程2过了休眠状态,之前的输出已经是2,所以自增后输出为3,又过了1秒&&我都快晕了,大概就是这意思吧,我想表达的就是:一个Timer开启的线程处理还没有完成,到了时间,另一Timer还会继续进入该方法进行处理。
那怎么解决这个问题呢?解决方案有三种,下面一一道来,适应不同的场景,不过还是推荐最后一种,比较安全。
★重入问题解决方案
1、使用lock(Object)的方法来防止重入,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就等待执行,适用重入很少出现的场景(具体也没研究过,可能比较占内存吧)。
代码跟上面差不多,在触发的方法中加入lock,这样当线程2进入触发的方法中,发现已经被锁,会等待锁中的代码处理完在执行,代码如下:
private static object locko = new object();&
&/// &summary&
&/// System.Timers.Timer的回调方法
&/// &/summary&
/// &param name="sender"&&/param&
/// &param name="args"&&/param&
private static void TimersTimerHandler(object sender, EventArgs args)
int t = ++ &br&&&&&&&& lock (locko)
&em id="__mceDel"&&&&&&&& {
&&&&&&&&&&&&Console.WriteLine(string.Format("线程{0}输出:{1},&&&&&& 输出时间:{2}", t, outPut.ToString(), DateTime.Now));
&&&&&&&&&&&&System.Threading.Thread.Sleep(2000);
&&&&&&&&&&&&outPut++;
&&&&&&&&&&&&Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(), DateTime.Now));
&&&&}&/em&
执行结果:
2、设置一个标志,表示一个Timer处理正在执行,下一个Timer发生的时候发现上一个没有执行完就放弃(注意这里是放弃,而不是等待哦,看看执行结果就明白啥意思了)执行,适用重入经常出现的场景。代码如下:
private static int inTimer = 0;
/// &summary&
/// System.Timers.Timer的回调方法
/// &/summary&
/// &param name="sender"&&/param&
/// &param name="args"&&/param&
private static void TimersTimerHandler(object sender, EventArgs args)
&&&&int t = ++
&&&&if (inTimer == 0)
&&&&&&&&inTimer = 1;
&&&&&&&&Console.WriteLine(string.Format("线程{0}输出:{1},&&&&&& 输出时间:{2}", t, outPut.ToString(), DateTime.Now));
&&&&&&&&System.Threading.Thread.Sleep(2000);
&&&&&&&&outPut++;
&&&&&&&&Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(), DateTime.Now));
&&&&&&&&inTimer = 0;
执行结果:
3、在多线程下给inTimer赋值不够安全,Interlocked.Exchange提供了一种轻量级的线程安全的给对象赋值的方法(感觉比较高上大,也是比较推荐的一种方法),执行结果与方法2一样,也是放弃执行。Interlocked.Exchange用法参考这里。
private static int inTimer = 0;
/// &summary&
/// System.Timers.Timer的回调方法
/// &/summary&
/// &param name="sender"&&/param&
/// &param name="args"&&/param&
private static void TimersTimerHandler(object sender, EventArgs args)
&&&&int t = ++
&&&&if (Interlocked.Exchange(ref inTimer, 1) == 0)
&&&&&&&&Console.WriteLine(string.Format("线程{0}输出:{1},&&&&&& 输出时间:{2}", t, outPut.ToString(), DateTime.Now));
&&&&&&&&System.Threading.Thread.Sleep(2000);
&&&&&&&&outPut++;
&&&&&&&&Console.WriteLine(string.Format("线程{0}自增1后输出:{1},输出时间:{2}", t, outPut.ToString(), DateTime.Now));
&&&&&&&&Interlocked.Exchange(ref inTimer, 0);
执行结果:
&img style="BACKGROUND-IMAGE: BORDER-BOTTOM: 0 BORDER-LEFT: 0 PADDING-LEFT: 0 PADDING-RIGHT: 0 DISPLAY: BORDER-TOP: 0 BORDER-RIGHT: 0 PADDING-TOP: 0px" title="image" border="0" alt="image" src="/upload//497.png" width="640" height="179"&
终于码完字了,真心不容易啊。写博客是个挺耗精力的事情,真心佩服那些大牛们笔耕不辍,致敬!在这里稍微总结一下,timer是一个使用挺简单的类,拿来即用,这里主要总结了使用timer时重入问题的解决,以前也没思考过这个问题,解决方案也挺简单,在这里列出了三种,主要参考在这里,不知道还有没有其他的方式。这里的解决方案同时也适用多线程的重入问题。时间不早了,洗洗睡了。
阅读(...) 评论()timer会独占线程吗如果不是那么如何做到隔一段时间然后继续执行命令??别告诉我用thread.sleep【c#吧】_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:115,206贴子:
timer会独占线程吗如果不是那么如何做到隔一段时间然后继续执行命令??别告诉我用thread.sleep,这个会独占线程
正版授权奇迹MU页游,奇迹重生!原汁原味还原奇迹,十年轮回!
对象运行都是要占线程的
小白告诉你,timer是窗体主线程
不是很懂。最近用sleep,也是发现会阻塞线程。现在用的是网上看到的一个方法。这个不会阻塞线程,单纯的延时,具体为什么我还没去了解过,估计就是application执行空事件吧,主函数那边的代码我从来没看过,估计是这么个意思
主窗体的timer是操作系统提供的功能
Timer我记得有三种,不知道你说的哪个,应该属于主线程,sleep会阻塞不要用,可以动态改变时钟周期来实现
timer有好几个,先搞清楚区别
登录百度帐号推荐应用C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析
投稿:shichen2014
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析,以实例形式较为详细的讲述了.NET Framework里面提供的三种Timer具体用法,需要的朋友可以参考下
本文实例讲述了C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析,分享给大家供大家参考。具体分析如下:
在.NET Framework里面提供了三种Timer
① System.Windows.Forms.Timer
② System.Timers.Timer
③ System.Threading.Timer
现分述如下:
一、System.Windows.Forms.Timer
1、基于Windows消息循环,用事件方式触发,在界面线程执行;是使用得比较多的Timer,Timer Start之后定时(按设定的Interval)调用挂接在Tick事件上的EvnetHandler。在这种Timer的EventHandler中可 以直接获取和修改UI元素而不会出现问题--因为这种Timer实际上就是在UI线程自身上进行调用的。
2、它是一个基于Form的计时器
3、创建之后,你可以使用Interval设置Tick之间的跨度,用委托(delegate)hook Tick事件
4、调用Start和Stop方法,开始和停止
5、完全基于UI线程,因此部分UI相关的操作会在这个计时器内进行
6、长时间的UI操作可能导致部分Tick丢失
代码如下:public partial class Form1 : Form
public Form1()
InitializeComponent();
int num = 0;
private void Form_Timer_Tick(object sender, EventArgs e)
label1.Text = (++num).ToString();
Thread.Sleep(3000);
private void button1_Click(object sender, EventArgs e)
Form_Timer.Start();
private void button2_Click(object sender, EventArgs e)
Form_Timer.Stop();
1、上面这个是一个很简单的功能,在Form窗体上拖了一个System.Windows.Forms.Timer控件名字为Form_Timer,在属性窗中把Enable属性设置为Ture,Interval是定时器的间隔时间。双击这个控件就可以看到 Form_Timer_Tick方法。在这个方法中,我们让她不停的加一个数字并显示在窗体上,2个按钮提供了对计时器的控制功能。
2、执行的时候你去点击其他窗体在回来,你会发现我们的窗体失去响应了。因为我们这里使用Thread.Sleep(3000);让当前线程挂起,而UI失去相应,说明了这里执行时候采用的是单线程。也就是执行定时器的线程就是UI线程。
3、Timer 用于以用户定义的事件间隔触发事件。Windows 计时器是为单线程环境设计的,其中,UI 线程用于执行处理。它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。
4、在Timer内部定义的了一个Tick事件,我们前面双击这个控件时实际是增加了一行代码
代码如下:this.Form_Timer.Tick += new System.EventHandler(this.Form_Timer_Tick);
然后Windows将这个定时器与调用线程关联(UI线程)。当定时器触发时,Windows把一个定时器消息插入到线程消息队列中。调用线程执行一个消息泵提取消息,然后发送到回调方法中(这里的Form_Timer_Tick方法)。而这些都是单线程进行了,所以在执行回调方法时UI会假死。所以使用这个控件不宜执行计算受限或IO受限的代码,因为这样容易导致界面假死,而应该使用多线程调用的Timer。另外要注意的是这个控件时间精度不高,精度限定为 55 毫秒。
二、System.Timers.Timer
1. 用的不是Tick事件,而是Elapsed事件
2. 和System.Windows.Forms.Timer一样,用Start和Stop方法
3. AutoReset属性决定计时器是不是要发起一次事件然后停止,还是进入开始/等待的循环。System.Windows.Forms.Timer没有这个属性
4. 设置对于UI控件的同步对象(synchronizing object),对控件的UI线程发起事件
代码如下:public partial class Form1 : Form
public Form1()
InitializeComponent();
int num = 0;
DateTime time1 = new DateTime();
DateTime time2 = new DateTime();
//定义Timer
System.Timers.Timer Timers_Timer = new System.Timers.Timer();
private void button1_Click(object sender, EventArgs e)
//手动设置Timer,开始执行
Timers_Timer.Interval = 20;
Timers_Timer.Enabled =
Timers_Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timers_Timer_Elapsed);
time1 = DateTime.N
void Timers_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
label1.Text = Convert.ToString((++num)); //显示到lable
Thread.Sleep(3000);
private void button2_Click(object sender, EventArgs e)
//停止执行
Timers_Timer.Enabled =
time2 = DateTime.N
MessageBox.Show(Convert.ToString(time2-time1));
三、System.Threading.Timer
代码如下:public partial class Form1 : Form
public Form1()
InitializeComponent();
int num = 0;
DateTime time1 = new DateTime();
DateTime time2 = new DateTime();
System.Threading.Timer Thread_T
private void button1_Click(object sender, EventArgs e)
Thread_Time = new System.Threading.Timer(Thread_Timer_Method,null,0,20);
time1 = DateTime.N
void Thread_Timer_Method(object o)
label1.Text = Convert.ToString((++num));
System.Threading.Thread.Sleep(3000);
private void button2_Click(object sender, EventArgs e)
Thread_Time.Dispose();
time2 = DateTime.N
MessageBox.Show(Convert.ToString(time2-time1));
1、用Threading.Timer时的方法,和前面就不太相同了,所以的参数全部在构造函数中进行了设置,而且可以设置启动时间。而且没有提供start和stop方法来控制计时器。而且是以一种回调方法的方式实现,而不是通过事件来实现的。他们之间还是有区别的。
2、我们只有销毁掉对象来停止他。当你运行时,你会发现他和前面的Timers.Timer一样,是多线程的,主要表现在不会假死,调试运行报错。但跟让你奇怪的是,我们的代码竟然无法让她停止下来。调用了Dispose方法没有用。问题在那?然后有进行了测试,修改了间隔时间为100,200,500,,4000。这几种情况。发现当间隔为500ms以上是基本马上就停止了。而间隔时间相对执行时间越短,继续执行的时间越长。这应该是在间隔时间小于执行时间时多个线程运行造成的。因为所有的线程不是同时停止的。间隔越短,线程越多,所以执行次数越多。
3、System.Threading.Timer 是一个简单的轻量计时器,它使用回调方法并由线程池线程提供服务。不建议将其用于 Windows 窗体,因为其回调不在用户界面线程上进行。
希望本文所述对大家的C#程序设计有所帮助。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具相关文章推荐
System.Timers.Timer t = new System.Timers.Timer(5000); //设置时间间隔为5秒
private void Form1...
.NET Framework里面提供了三种Timer:
System.Windows.Forms.Timer
System.Timers.Timer
System.Threa...
System.Timers.Timer t = new System.Timers.Timer(5000); //设置时间间隔为5秒
private void Form1_Loa...
System.Timers.Timer
定时执行程序
System.Timers.Timer t = new System.Timers.Timer(5000); /...
System.Timers.Timer和System.Windows.Forms.Timer是有区别的。
我一个是非堵塞的,一个不是。更重要的的System.Timer是多线程的,如果控制不好执行时...
经过查找资料,发现timer控件的timer.start();方法不能从非Ui的线程启动。
每隔一定的时间,触发去做指定的事情,可以用timer类。
Timer timer = new Timer(timerDelegate, ParamObject, )
如果你需要使用规律的时间间隔重复执行一些方法,最简单的方式是使用定时器(timer)。与下边的例子相比,定时器可以便捷、高效地使用内存和资源:
他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)共有2270位成员   人气指数 -   最新排名 -
【话题】多个timer并发遇到的问题
22:25:25 来自:李祎然 浏览数:96次
我在尝试用二十个timer控制二十个电磁阀的通断,要求是接到信号后延时几十毫秒,再联通几十毫秒之后断开。
多数时候没有信号但可能同一时刻多个电磁阀收到信号,也可能同一个电磁阀在几十毫秒内连续收到信号
我在使用threading.timer时遇到的问题是一旦短时间内接到大量信号,部分timer好像无法正确触发,表现为个别电磁阀开启后没有正常断开
而换成form.timer能保证正常通断,但同时打开的timer多了却会阻塞用户界面,另外据说form.timer是单线程的,我不知道用它是否能在同时接到多个信号时使相应的电磁阀同时打开,还是说会排队之后串行工作?
请大家帮忙看看我应该采取什么控制方案,谢谢。
jim6601回复于24日22点38分 
实际上最关键地,就是不要在接收到信号之后去创建、释放线程,而仅在程序开始时创建一次。
火城狂神回复于24日22点49分 
虽然不知道你通过什么连接的电磁阀,但可以肯定的是你的控制信号不可以同时控制二十个电磁阀。也就是说,你需要加锁来操作,当一个计时器开始触发工作时,其它计时器的触发回调函数中要等待锁的释放,保证依次对电磁阀发出控制信号。
春眠不觉晓回复于24日23点04分 
我的思路是这样,一个进程监听开关量的树组, 就负责定时执行开关电磁阀操作. 间隔比如几十毫秒根据数组做一遍开关操作.
其它的进程负责组织这个数组.
cepke回复于24日23点19分 
建一个后台线程就可以了.只要后台线程不停地定时触发委托事件,别的事让主线程去做就可以了.当然,事件里得有相应的参数(如:第几个控制阀),当然,事件接收处理的时候要保证线程安全.
迟旻皓回复于24日23点33分 
按说threading.timer就是多线程的啊,用的时候哪怕同时触发的再多再频繁也没有阻塞用户界面
但就是隔三差五的有一个电磁阀关不上,我在timer里就做了两件事,一是控制通断,二是变一下界面上相应的label,电磁阀没关上时相应的lable也没有变化所以应该是timer没有触发没错。
或者还有什么多线程方案能控制时间的?
春草回复于24日23点47分 
看看电磁阀控制代码,是不是在频繁触发事件影响了状态判断?
czx1203回复于25日02点54分 
按说不会,用form.timer时没问题说明代码在单线程下没事,而我的状态变量是用interlocked改的,应该也不存在多线程冲突。
threading.timer归线程池管,现在怀疑可能是多个同时触发时超了.net默认的25个线程的上限。
xiaoniuniu_97回复于25日03点13分 
timer有这么复杂吗?
happywork0828回复于25日03点28分 
你做个实验就知道了,两个计时器都是100毫秒触发一次,但第一个计时器里有一个操作要执行1秒(我这里就是sleep(1000)替代),你会发现10秒后当第一个计时器执行了10次后第二个计时器也执行了10次,而按你的想法是第二个计时器应该执行10×10=100次了
using System.C
using System.Collections.G
using System.D
using System.D
using System.L
using System.T
using System.Windows.F
namespace WindowsFormsApplication32
public partial class Form1 : Form
int A = 0, B = 0;
public Form1()
InitializeComponent();
Timer T1 = new Timer();
T1.Interval = 100;
T1.Tick += new EventHandler(T1_Tick);
T1.Enabled =
Timer T2 = new Timer();
T2.Interval = 100;
T2.Tick += new EventHandler(T2_Tick);
T2.Enabled =
L = new Label();
L.Parent =
L.AutoSize =
void T2_Tick(object sender, EventArgs e)
L.Text = &第一个计时器运行了& + (++A).ToString() + &次 第二个计时器运行了& + B.ToString() + &次&;
System.Threading.Thread.Sleep(1000);
void T1_Tick(object sender, EventArgs e)
L.Text = &第一个计时器运行了& + A.ToString() + &次 第二个计时器运行了& + (++B).ToString() + &次&;
hujingdu回复于25日03点42分 
线程中sleep并不会使得其它线程排队,而Form.Timer实际是在主线程中触发所以才会排队。
对于windows,确实有控制时序精度问题。即使WinCE那种专为工业控制而设计的,也是不能有很高的精度。
如果这确实是个问题,可能确实需要去找找看有没有现成的第三方Timer。
ar468030回复于25日03点54分 
VB使用多线程就可解决这个问题!
xiaocui6033回复于25日04点13分 
为什么要用到Timer?
霍晟悦回复于25日04点27分 
to wartim:
谢谢你的代码,我试过了,form.timer确实只能运行一个。
to sp1234:
精度的问题我暂时不管了,我觉得奇怪的就是明明threading.timer是多线程的,我建立的全局静态实例,用.change控制timer的开关,没有重复的建立销毁,为什么会有遗漏触发的现象?
wenjinghjkl回复于25日04点41分 
十分感谢,我先去试一下
我是有一个独立的线程在不停的分析接收到的数据并随时通过begininvoke发送信号
所以我担心轮询的频率慢了会延缓信号相应甚至漏过信号,而频率高了(大概要一秒几十次才能保证触发的时间大致准确?)占用过多的cpu资源又会影响数据分析线程的速度……
加油123回复于25日04点55分 
呃,能说下具体怎么做吗?
多线程好办,可控制时间不还是要用到timer?
anglemaddy回复于25日05点09分 
一个32位数字量输出卡,指令信号本身是加着锁的应该不会因为多线程冲突造成指令出错。
gocrazy回复于25日05点22分 
主要是我担心线程sleep之后还要排队等操作系统相应不能马上执行,毕竟我的windows的精度就在10毫秒以上
控制几十毫秒的延时已经有些勉强了
yz200309回复于25日05点31分 
我不知道你是如何“接到信号的”。假设放到单个线程中更合适,那么可以这样:
1. 创建20个线程对应每一个电磁阀,但是不启动。
2. 主线程只是用于轮询接收信号(当然轮询时要Sleep),每当接收到信号,对于每一个电磁阀的线程,执行Start()。线程中执行的方法执行:Sleep几十毫秒、然后联通,然后Sleep几十毫秒,然后断开,线程方法结束。
我不知道当接到信号时如果电磁阀的控制线程正在执行,应该如何处理逻辑。你也没有写。但是判断线程是否Active是很容易的,.net线程有这个功能。
携手共勉回复于25日05点46分 
timer是这样,一个timer的事件如果要执行1个小时,其它的都会阻塞等待,试试多线程
C#开发的其他话题...
热门脚本语言:}

我要回帖

更多关于 matlab timer 多线程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信