static void Main(string[] args)
{
Thread ThrdA = new Thread(FunA);
ThrdA.Start();
Console.ReadLine();
}
public static void FunA()
{
Timer timerA = new Timer(new TimerCallback(A), null,0, 3000);
}
public static void A(object a)
{
Console.WriteLine("{0}", Thread.CurrentThread.ManagedThreadId);
}
这样的代码会一直正常输出Thread.CurrentThread.ManagedThreadId的值;
static void Main(string[] args)
{
Thread AThrd = new Thread(AutoAddFun);
Thread RThrd = new Thread(AutoReadFun);
AThrd.Start();
RThrd.Start();
Console.ReadLine();
}
static List<int> numList = new List<int>();
static ReaderWriterLock rwl = new ReaderWriterLock();
public static void AutoAddFun()
{
Timer timerAdd = new Timer(new TimerCallback(Add), null, 0, 3000);
}
public static void AutoReadFun()
{
Timer timerRead1 = new Timer(new TimerCallback(Read), null, 0, 1000);
Timer timerRead2 = new Timer(new TimerCallback(Read), null, 0, 1000);
Timer timerRead3 = new Timer(new TimerCallback(Read), null, 0, 1000);
}
public static void Add(object obj)
{
var num = new Random().Next(0, 1000);
rwl.AcquireWriterLock(TimeSpan.FromSeconds(30));
numList.Add(num);
Console.WriteLine("我是线程{0},我插入的数据是{1}。", Thread.CurrentThread.ManagedThreadId, num);
rwl.ReleaseWriterLock();
}
public static void Read(object obj)
{
rwl.AcquireReaderLock(TimeSpan.FromSeconds(30));
Console.WriteLine("我是线程{0},我读到的集合是{1}.", Thread.CurrentThread.ManagedThreadId, string.Join(",", numList));
rwl.ReleaseReaderLock();
}
这是@一线码农 的源码,讲解ReadWriterLock方面的知识点,运行代码一段时间后会停止输出,在所有定时器的回调函数中打了断点均没有中断,说明定时器已经停止了,在上下文中并没有主动将定时器停止,我想请问这个过程大概是怎样的。谢谢。
9 个解决方案
#1
浮起来!
#2
麻里麻里哄
#3
锲而不舍
#4
你确定这个代码是终止掉了,而不是进入死锁了?
#5
所谓死锁,就是Add在等待Read,同时Read也在等待Add
#6
凑巧而已,你测试时你的Timer正好没有被垃圾回收
试试改成这样,说不定Timer就不会继续跑了:
var ThrdA = new Thread(FunA);
ThrdA.Start();
for (int i = 0; i < 10; i++)
{
var s = new int[100000000];
}
Console.ReadLine();
试试改成这样,说不定Timer就不会继续跑了:
var ThrdA = new Thread(FunA);
ThrdA.Start();
for (int i = 0; i < 10; i++)
{
var s = new int[100000000];
}
Console.ReadLine();
#7
public static void Add(object obj)
{
var num = new Random().Next(0, 1000);
try
{
rwl.AcquireWriterLock(TimeSpan.FromSeconds(30));
try
{
numList.Add(num);
Console.WriteLine("我是线程{0},我插入的数据是{1}。", Thread.CurrentThread.ManagedThreadId, num);
}
finally
{
rwl.ReleaseWriterLock();
}
}
catch (ApplicationException)
{
rwl.ReleaseWriterLock();
}
}
我修改了部分代码(同样修改了Read部分),如果死锁,请求便超时,同时抛出ApplicationException异常,实际上并没有抛出异常。所以,我想应该不是死锁的问题。
#8
原因很简单,计时器被GC了。在MSDN里有一段话:
只要在使用 Timer,就必须保留对它的引用。 对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。 即使 Timer 仍处在活动状态,也会被回收。
http://msdn.microsoft.com/zh-cn/library/system.threading.timer(v=vs.110).aspx
只要在使用 Timer,就必须保留对它的引用。 对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。 即使 Timer 仍处在活动状态,也会被回收。
http://msdn.microsoft.com/zh-cn/library/system.threading.timer(v=vs.110).aspx
#9
是呀,@phommy的评论提醒了我往GC方面想,在@teof的博客上看到上面那句话,豁然开朗!
而且,回调方法不在创建计时器的线程上执行,而是在系统提供的ThreadPool线程上执行。呵呵
#1
浮起来!
#2
麻里麻里哄
#3
锲而不舍
#4
你确定这个代码是终止掉了,而不是进入死锁了?
#5
所谓死锁,就是Add在等待Read,同时Read也在等待Add
#6
凑巧而已,你测试时你的Timer正好没有被垃圾回收
试试改成这样,说不定Timer就不会继续跑了:
var ThrdA = new Thread(FunA);
ThrdA.Start();
for (int i = 0; i < 10; i++)
{
var s = new int[100000000];
}
Console.ReadLine();
试试改成这样,说不定Timer就不会继续跑了:
var ThrdA = new Thread(FunA);
ThrdA.Start();
for (int i = 0; i < 10; i++)
{
var s = new int[100000000];
}
Console.ReadLine();
#7
public static void Add(object obj)
{
var num = new Random().Next(0, 1000);
try
{
rwl.AcquireWriterLock(TimeSpan.FromSeconds(30));
try
{
numList.Add(num);
Console.WriteLine("我是线程{0},我插入的数据是{1}。", Thread.CurrentThread.ManagedThreadId, num);
}
finally
{
rwl.ReleaseWriterLock();
}
}
catch (ApplicationException)
{
rwl.ReleaseWriterLock();
}
}
我修改了部分代码(同样修改了Read部分),如果死锁,请求便超时,同时抛出ApplicationException异常,实际上并没有抛出异常。所以,我想应该不是死锁的问题。
#8
原因很简单,计时器被GC了。在MSDN里有一段话:
只要在使用 Timer,就必须保留对它的引用。 对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。 即使 Timer 仍处在活动状态,也会被回收。
http://msdn.microsoft.com/zh-cn/library/system.threading.timer(v=vs.110).aspx
只要在使用 Timer,就必须保留对它的引用。 对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。 即使 Timer 仍处在活动状态,也会被回收。
http://msdn.microsoft.com/zh-cn/library/system.threading.timer(v=vs.110).aspx
#9
是呀,@phommy的评论提醒了我往GC方面想,在@teof的博客上看到上面那句话,豁然开朗!
而且,回调方法不在创建计时器的线程上执行,而是在系统提供的ThreadPool线程上执行。呵呵