C# 重置System.Timers.Timer以防止已发生事件
我正在尝试使用C# 重置System.Timers.Timer以防止已发生事件,c#,asp.net,static,timer,C#,Asp.net,Static,Timer,我正在尝试使用计时器触发事件,以便通过网络发送数据。我创建了一个简单的类进行调试。基本上我有一个列表我想发送。我希望发生以下情况: 将字符串添加到列表中 启动计时器10秒 将第二个字符串添加到计时器之前的列表中 在10秒后重新启动计时器 到目前为止,我有: public static List<string> list; public static Timer timer; public static bool isWiredUp = false; public static vo
计时器
触发事件,以便通过网络发送数据。我创建了一个简单的类进行调试。基本上我有一个列表
我想发送。我希望发生以下情况:
列表中
计时器10秒
计时器之前的列表中
public static List<string> list;
public static Timer timer;
public static bool isWiredUp = false;
public static void Log(string value) {
if (list == null) list = new List<string>();
list.Add(value);
//this does not reset the timer, elapsed still happens 10s after #1
if (timer != null) {
timer = null;
}
timer = new Timer(10000);
timer.Start();
timer.Enabled = true;
timer.AutoReset = false;
if (!isWiredUp) {
timer.Elapsed += new ElapsedEventHandler(SendToServer);
isWiredUp = true;
}
}
static void SendToServer(object sender, ElapsedEventArgs e) {
timer.Enabled = false;
timer.Stop();
}
公共静态列表;
公共静态定时器;
公共静态bool isWiredUp=false;
公共静态无效日志(字符串值){
如果(list==null)list=newlist();
列表。添加(值);
//这不会重置计时器,经过的时间仍然发生在#1之后10秒
如果(计时器!=null){
定时器=空;
}
定时器=新定时器(10000);
timer.Start();
timer.Enabled=true;
timer.AutoReset=false;
如果(!isWiredUp){
timer.appeased+=新的ElapsedEventHandler(SendToServer);
isWiredUp=true;
}
}
静态void SendToServer(对象发送方,ElapsedEventArgs e){
timer.Enabled=false;
timer.Stop();
}
有什么想法吗?你所实施的方法完全是错误的。看看消费者-生产者模型: 您试图做的通常称为消费者/生产者数据流模型。从本质上说,您可以生成一个要发送到某处的数据列表,而不是每次向列表中添加一个项目时都发送它,您可以分组发送这些项目。。因此,您有一个生产者(发送数据的代码)和一个消费者(发送数据的代码) 通常,这个问题可以通过生成一个线程来解决,该线程监视列表(通常是一个队列)并定期发送数据,最好的方法是使用EventWaitHandle 下面是一些非常简化的代码作为示例
class ServerStuff
{
public void Init()
{
datatosend = new List<string>();
exitrequest = new EventWaitHandle(false, EventResetMode.ManualReset); //This wait handle will signal the consumer thread to exit
Thread t = new Thread(new ThreadStart(_RunThread));
t.Start(); // Start the consumer thread...
}
public void Stop()
{
exitrequest.Set();
}
List<string> datatosend;
EventWaitHandle exitrequest;
public void AddItem(string item)
{
lock (((ICollection)datatosend).SyncRoot)
datatosend.Add(item);
}
private void RunThread()
{
while (exitrequest.WaitOne(10 * 1000)) //wait 10 seconds between sending data, or wake up immediatly to exit request
{
string[] tosend;
lock (((ICollection)datatosend).SyncRoot)
{
tosend = datatosend.ToArray();
datatosend.Clear();
}
//Send the data to Sever here...
}
}
}
classserverstuff
{
公共void Init()
{
datatosend=新列表();
exitrequest=new EventWaitHandle(false,EventResetMode.ManualReset);//此等待句柄将向使用者线程发出退出的信号
线程t=新线程(新线程开始(_RunThread));
t、 Start();//启动使用者线程。。。
}
公共停车场()
{
exitrequest.Set();
}
列出要发送的数据;
EventWaitHandle exitrequest;
公共无效附加项(字符串项)
{
锁定(((ICollection)datatosend.SyncRoot)
datatosend.Add(项目);
}
私有void RunThread()
{
while(exitrequest.WaitOne(10*1000))//在发送数据之间等待10秒,或者立即唤醒以退出请求
{
字符串[]tosend;
锁定(((ICollection)datatosend.SyncRoot)
{
tosend=datatosend.ToArray();
datatosend.Clear();
}
//将数据发送到此处的服务器。。。
}
}
}
您可以使用停止
功能,然后立即使用启动
功能“重新启动”计时器。使用它,您可以在第一次创建类时创建计时器
,连接当时发生的事件,然后在添加项时只调用这两个方法。它将启动或重新启动计时器。请注意,在尚未启动的计时器上调用Stop
,没有任何作用,不会引发异常或导致任何其他问题
public class Foo
{
public static List<string> list;
public static Timer timer;
static Foo()
{
list = new List<string>();
timer = new Timer(10000);
timer.Enabled = true;
timer.AutoReset = false;
timer.Elapsed += SendToServer;
}
public static void Log(string value)
{
list.Add(value);
timer.Stop();
timer.Start();
}
static void SendToServer(object sender, ElapsedEventArgs e)
{
//TODO send data to server
//AutoReset is false, so neither of these are needed
//timer.Enabled = false;
//timer.Stop();
}
}
公共类Foo
{
公共静态列表;
公共静态定时器;
静态Foo()
{
列表=新列表();
定时器=新定时器(10000);
timer.Enabled=true;
timer.AutoReset=false;
timer.appeased+=SendToServer;
}
公共静态无效日志(字符串值)
{
列表。添加(值);
timer.Stop();
timer.Start();
}
静态void SendToServer(对象发送方,ElapsedEventArgs e)
{
//TODO向服务器发送数据
//AutoReset为false,因此不需要这两个选项
//timer.Enabled=false;
//timer.Stop();
}
}
请注意,与使用
列表相比,您很可能希望使用阻止集合
。这有几个优点。首先,如果同时从多个线程调用Log
方法,则该方法将起作用;按原样,多个并发日志可能会破坏列表。这还意味着SendToServer
可以在添加新项目的同时将项目移出队列。如果使用列表
,则需要锁定对列表的所有访问权限(这可能不是问题,但不是那么简单)。使用IObservable(Rx)很容易实现这类功能
让我们通过声明一个主题
作为您的列表来简化问题,并继续使用.OnNext。一旦你有了一个可观察的对象,你就可以用System.Reactive.Linq的一条“线”做你想做的事情。这在下面的伪c中进行了说明#
主题
.Buffer(,1)//缓冲区,直到添加值或超时过期
.订阅(x=>
{
如果(x.Count==0)//超时已过期,请继续发送
{
SendAccumeratedListToServer();
}
其他的
{
.添加(x);
}
});
您的链接显示“此主题已过时”。并且没有包含有用的信息。我不知道您在谈论什么,也不知道该页面应该告诉我什么。这看起来更容易理解。我现在接受了另一个答案,我有一个会议,但会在会议结束后再看你的回答。如果您没有重置它,并且具有AutoReset=true
,同样的事情也会发生。当它没有设置为自动重置,并且在添加项目时重置时,情况就完全不同了。2.然后添加它,使您的代码按照问题的要求执行。3.不,不是。如果你想要证据,
subject
.Buffer(<your timespan>,1) //buffer until either a value is added or the timeout expires
.Subscribe(x =>
{
if (x.Count == 0) //the timeout expired so send on
{
SendAccumulatedListToServer(<your list>);
<clear your list>
}
else
{
<your list>.Add(x);
}
});