c# lock锁与 Threading.Timer 结合使用的问题 , 大版主进来啊

purexiafeng 2008-05-07 05:58:30

System.Threading.Timer fTimer = new System.Threading.Timer(new TimerCallback(TaskService.DoTask), new AutoResetEvent(false), 0, 1000);


public void DoTask(Object stateInfo)
{
lock (this)
{
//任务代码
}
}

当我 fTimer.Dispose();//停止了时间后,可以 任务代码 还在执行。经过我调式N次发现是在lock里阻塞了线程。当我
fTimer.Dispose()停止后即使把fTimer = null ; //任务代码 还是在执行。。。。我想问我怎么做 才可以把这些阻塞了线程立刻释放掉。简单的意思就是立刻停止它
...全文
2320 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
不老神仙 2010-03-02
  • 打赏
  • 举报
回复
学习了 西多款飞机电井
leisurelymyth 2009-08-23
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 silwol 的回复:]
LZ是这样的:你的fTimer每秒钟都会调用一次DoTask,且同一时间只会有一个DoTask在运行,如果此时已有一个DoTask在运行,那么后面的将被lock在那里等着
LZ你这么做一是为了同一时间只做一个DoTask,二是为了保证执行的顺序吧?
实际上,当DoTask里的操作超过1秒时,后面的DoTask都会被lock在那里。比如我的fTimer运行了9秒多,那么应该有总共10个DoTask,假设DoTask要执行2秒钟,那么当你在9秒多停止fTimer的时候,实际上才运行到第5个DoTask(左右),后面还有5个DoTask被lock着呢
LZ可以看下这个
C# codeusing System;using System.Collections.Generic;using System.Text;using System.Threading;namespace ConsoleApplication1
{class Program
{staticvoid Main(string[] args)
{

Test t=new Test();while (t.Enabled) ;
Console.WriteLine("STOPING:"+ t.Value);
t.Stop();
Console.WriteLine("STOPPED:"+ t.Value);
Console.ReadLine();
}
}publicclass Test
{
System.Threading.Timer fTimer;privateint i=0;
System.Timers.Timer timer;publicint Value
{get
{return i;
}
}publicbool Enabled
{get
{return timer.Enabled;
}
}public Test()
{
fTimer=new System.Threading.Timer(new TimerCallback(this.DoTask),new AutoResetEvent(false),0,1000);
timer=new System.Timers.Timer(10000);
timer.Elapsed+=new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled=true;
}privatevoid timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timer.Enabled=false;
}publicvoid DoTask(Object stateInfo)
{lock (this)
{
Console.WriteLine(i++);
Thread.Sleep(2000);
}
}publicvoid Stop()
{
fTimer.Dispose();
}
}
}
[/Quote]
csShooter 2008-05-08
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 silwol 的回复:]
LZ我的意思是这样的:
你不是要每秒钟提交一次数据,而且同一时间只能提交一个数据么?
所以我的想法是,建立个Queue buffer,当作是发送数据的缓冲区,你用Timer每1秒钟向里面添加一次数据;然后运行一个线程,不断循环从Queue buffer里面取数据,发送;Timer停止的时候,把发送的线程也停止掉。

C# code// 每秒钟运行下AddMsg,把数据放到Queue buffer里
System.Threading.Timer fTimer = new System.Threading.Tim…
[/Quote]
silwol 2008-05-08
  • 打赏
  • 举报
回复
LZ我的意思是这样的:
你不是要每秒钟提交一次数据,而且同一时间只能提交一个数据么?
所以我的想法是,建立个Queue buffer,当作是发送数据的缓冲区,你用Timer每1秒钟向里面添加一次数据;然后运行一个线程,不断循环从Queue buffer里面取数据,发送;Timer停止的时候,把发送的线程也停止掉。
// 每秒钟运行下AddMsg,把数据放到Queue buffer里
System.Threading.Timer fTimer = new System.Threading.Timer(new TimerCallback(AddMsg), new AutoResetEvent(false), 0, 1000);
public void AddMsg()
{
// 你把要发送的数据msg放到Queue buffer里
}
public void SendMsg()
{
// 每次从Queue buffer里取一个数据,然后发送
while(true)
{
msg = buffer.Dequeue();
// 做你的DoTask
}
}
// 你用个Thread执行SendMsg,当你执行fTimer.Dispose()后,再加个语句把Thread停止掉

既然你每次只能有一个DoTask在运行,倒不如做个后台线程,里面while(true) { DoTask(); }
purexiafeng 2008-05-08
  • 打赏
  • 举报
回复
如果在LOCK前面排队的任务数量达到线程池 的上限后程序会出什么问题.
purexiafeng 2008-05-08
  • 打赏
  • 举报
回复
gomoku:
很感谢gomoku提供的
ThreadPool.GetAvailableThreads(out threadsLeft, out dummy);
if (threadsLeft < 2) return;
这段的代码.这样写后是不是代表 LOCK后面等待的任务都不会执行了.直接Return ,我看你在后面还是加了
LOCK ,这样应该没必要+LOCK了吧

对于gomoku所说的不用timer和lock的方法我最初也用过,一个单线程里写个死循环.但是感觉这样写
效率不是很好.因为我的任务里需要每多少秒执行一次.而多少秒是用户设置的.如果这样写会使调用不准时
而有timer和lock的任务时.只要执行任务的时间在多少秒里.调用还是准时的.
purexiafeng 2008-05-08
  • 打赏
  • 举报
回复
真心感谢大家热心的回答.如上所述 ,我现在确实是加了个标识位,但感觉不是最好的方法.
gomoku:
1.正如 :gomoku 所说的第5条 必须等前一个工作做完了才会去掉 读我那设定的 标识位.

silwol:
至于 silwol所说的建立个队列.把要提交的数据放进去.不是太懂你的意思.你的意思是要我放弃TIMER.
自己来写线程池吗...

myminimouse:
只有用LOCK来帮我使程序串行化.而且LOCK出来就是解决程序重入的.他就是来解决多线程的问题.要不
你以为LOCK是来解决什么的

大家:我主要是想我们现在讨论的LOCK后面等待的任务.能不能有什么代码可以释放掉他.昨晚我反编译了TIMER...结果全部是调用的API...头大.
myminimouse 2008-05-08
  • 打赏
  • 举报
回复
lz对锁还没有理解,即lock到底是锁了什么东西


如果要保证每次只有一个在向远程提交数据,那为什么还要用多线程呢?
yagebu1983 2008-05-08
  • 打赏
  • 举报
回复
用线程池不行吗?
gomoku 2008-05-08
  • 打赏
  • 举报
回复
1、下面只解释你的问题,并不是达到你目的的最好方法。

2、Threading.Timer的工作方式是这样的。每次时钟到点时,Timer从线程池中取出一个线程来运行回调函数。如果该回调函数在下次时钟到点前还没来得及结束,那么,可能会有多个线程同时在执行该函数。如果线程池中没有空闲的线程可用,回调函数就要排队等候。

3、Timer被取消后,它就不再安排新的回调函数,但是已经在运行的,或已经在排队的回调函数并没有被取消。所以当你fTimer.Dispose();停止了时间后,任务代码还在执行。

4、改进的方法。首先判断一下当前线程池中剩余可用线程的数目,如果小于一定数量,回调函数立刻返回。这样可以减少排队的回调函数。
其次,设置一个‘工作中’的标志,如果回调函数看到该标志被放倒了,它也应该立刻返回。

5、即使经过如上改进后,Timer被取消后,线程池中线程也不会立刻完成 - 正在做‘任务代码’的那个线程得把任务作完了才有机会观察到‘工作中’标志。不过从这时起,所有回调函数将迅速返回。

6、如果你程序退出了,线程池整个就被停止了,当然你所有的任务代码也就被停止了。如果你的任务代码没有需要清理的东西,这也是一种关闭方式。


class TaskService
{
volatile bool running = true;

public void DoTask(Object stateInfo)
{
int threadsLeft, dummy;
ThreadPool.GetAvailableThreads(out threadsLeft, out dummy);
if (threadsLeft < 2) return; //<----

lock (this)
{
if (!running) return; //<----
//任务代码
}
}

public void test()
{
using (System.Threading.Timer fTimer = new Timer(new TimerCallback(DoTask), null, 0, 1000))
{
Console.ReadLine();

fTimer.Change(0, Timeout.Infinite);
running = false;
}
Console.ReadLine();
}

static void Main()
{
new TaskService().test();
}
}





没有用lock和Timer的方法:


volatile bool running = true;

public void DoTasks()
{
DateTime last = new DateTime();

while (running)
{
DateTime current = DateTime.Now;
int elasped = (int) (current - last).TotalMilliseconds;
last = current;

if (elasped < 1000)
{
Thread.Sleep(Math.Min(1000, 1000 - elasped));
}
//任务代码...
}
}
purexiafeng 2008-05-08
  • 打赏
  • 举报
回复
恩.呵呵.感谢.结帐
很久没来CSDN.本来还以为CSDN彻底被娱乐化了...越半越垃圾.
想不到还是有很多象silwol gomoku的高手,谢谢了
silwol 2008-05-08
  • 打赏
  • 举报
回复
我也不清楚
但我相信,一个存放了n个数据的Queue,应该比n个被lock在那里等着运行的DoTask线程要好吧
purexiafeng 2008-05-08
  • 打赏
  • 举报
回复
Queue buffer 假如有大量的任务在里面等待会不会耗费资源哦..
我是不是需要对Queue buffer大小控制下
purexiafeng 2008-05-08
  • 打赏
  • 举报
回复
感谢 silwol 耐心的回答.
我大概明白你的意思.
不过这样做 如果 Queue buffer 数组里有很多等待任务的话.程序会不会有问题
silwol 2008-05-07
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 purexiafeng 的回复:]
引用 2 楼 51Crack 的回复:
为什么lock


我要保证每次只有一个在向远程提交数据。如果要是N个线程都在向远程提交数据。服务器吃不消的
[/Quote]
LZ,如果你的这个提交数据是很重要的,必须要执行的,那么就不能在Timer停止的时候立即结束,必须等所有的DoTask都提交完数据;如果不是,你就是要Timer停止的时候结束正在进行的和所有在等待的DoTask,我建议你用个Queue,然后把要提交的数据放到里面,比如就是1秒钟放1个,然后在一个线程thread里
while(true)
{
if (queue.Count != 0)
{
msg = queue.Dequeue();
....
}
}

当Timer停止的时候,你就可以把thread终止掉了
ziseliuxingzh 2008-05-07
  • 打赏
  • 举报
回复
想想能不能在lock里面的这段代码做文章,里面设置标志看看
fuadam 2008-05-07
  • 打赏
  • 举报
回复
.net的timer不太好用
wenbin 2008-05-07
  • 打赏
  • 举报
回复
感觉不要使用lock做,可以使用线程同步做
停止掉线程,如何立刻停止掉
使用超时?设定标志位?
一直没什么好的方法解决这个问题,
足球中国 2008-05-07
  • 打赏
  • 举报
回复
[Quote=引用楼主 purexiafeng 的帖子:]

System.Threading.Timer fTimer = new System.Threading.Timer(new TimerCallback(TaskService.DoTask), new AutoResetEvent(false), 0, 1000);


public void DoTask(Object stateInfo)
{
lock (this)
{
//任务代码
}
}

当我 fTimer.Dispose();//停止了时间后,可以 任务代码 还在执行。经过我调式N次发现是在lo…
[/Quote]
当停止线程时.线程并不会马上停止.要执行完所有的工作后才会停止.
new AutoResetEvent(false), 也不明白这里用这个是啥意思..
silwol 2008-05-07
  • 打赏
  • 举报
回复
LZ是这样的:你的fTimer每秒钟都会调用一次DoTask,且同一时间只会有一个DoTask在运行,如果此时已有一个DoTask在运行,那么后面的将被lock在那里等着
LZ你这么做一是为了同一时间只做一个DoTask,二是为了保证执行的顺序吧?
实际上,当DoTask里的操作超过1秒时,后面的DoTask都会被lock在那里。比如我的fTimer运行了9秒多,那么应该有总共10个DoTask,假设DoTask要执行2秒钟,那么当你在9秒多停止fTimer的时候,实际上才运行到第5个DoTask(左右),后面还有5个DoTask被lock着呢
LZ可以看下这个
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{

Test t = new Test();
while (t.Enabled) ;
Console.WriteLine("STOPING:" + t.Value);
t.Stop();
Console.WriteLine("STOPPED:" + t.Value);
Console.ReadLine();
}
}
public class Test
{
System.Threading.Timer fTimer;
private int i = 0;
System.Timers.Timer timer;

public int Value
{
get
{
return i;
}
}
public bool Enabled
{
get
{
return timer.Enabled;
}
}

public Test()
{
fTimer = new System.Threading.Timer(new TimerCallback(this.DoTask), new AutoResetEvent(false), 0, 1000);
timer = new System.Timers.Timer(10000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Enabled = true;
}

private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
timer.Enabled = false;
}

public void DoTask(Object stateInfo)
{
lock (this)
{
Console.WriteLine(i++);
Thread.Sleep(2000);
}
}

public void Stop()
{
fTimer.Dispose();
}
}
}
加载更多回复(15)

111,080

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧