C#锁阻塞或在锁之间长时间睡眠
本文关键字:长时间 之间 | 更新日期: 2023-09-27 18:27:45
我有一个程序,它有并行线程计时器。基本上,这些计时器设置为每10秒运行一次方法。在这种方法中,线程获得了一个列表上的锁,以制作一个副本来完成它的工作。
private object access = new object();
PeriodTask(){
lock(access){
copy = list.Where(e => e.valid).toList();
}
foreach (var element in copy)
do some not so quick work.
}
我还有一种方法可以获得关于那些同样需要锁的元素的信息。并获得一份
informationMethod(){
lock(access){
return list.Select(element => new serializableElement(element)).toList()
}
}
我需要锁的原因是,有一些方法可以添加和删除这个列表中的项目,也可以锁定它。但我甚至还没有给他们打电话。
我遇到的问题是,信息检索方法在这个类的实例之间阻塞或休眠了很长一段时间。可能有大约10个,似乎一次可以访问2或3个,但这个过程可能需要一分半到两分钟才能访问所有这些。我提到的第一个在计时器上执行的方法在应该访问的时候可以很好地访问,并立即释放锁,但另一个方法即使是执行的主线程,也很难执行。
我有几个测试实例化了这些类的管理器。
//sets up updaters test
var manager = new manager(config);
Assert.IsNotNull(manager);
Assert.IsFalse(manager.UpdatersRunning);
Assert.AreNotEqual(0, manager.Updaters.Count());//calls the informationMethod on each updater
manager.Dispose();
//This test doesn't even run the period task
//Waits to start updaters test
var manager = new StatusObjectManager(config);
Assert.IsNotNull(manager);
Assert.AreNotEqual(0, manager.Updaters.Count());
Assert.IsFalse(manager.UpdatersRunning);
Assert.AreEqual(0, manager.Updaters.Count(u => u.Running));
manager.StartUpdaters();
Assert.IsTrue(manager.UpdatersRunning);
Assert.AreNotEqual(0, manager.Updaters.Count(u => u.Running));
manager.Dispose();
//This test runs the period tasks and checks to make sure their running. Or at least 1.
//THis test takes a long time for the first informationMethod bout but not the other 2.
The code in the manager looks like this
return updaters.select(u => new serialUpdater(su));
此时不需要锁定,因为该列表未被修改。
有人知道可能发生了什么吗?我不知道如何判断线程是在锁上阻塞还是只是睡了一段不正常的时间。
这里的第一步是添加日志记录。简单的Trace.WriteLine
在锁之前和锁内部,您还可以在创建时获取/设置Thread.CurrentThread.Name
,读取Thread
,这样您就可以判断方法中有哪个Thread
。
下一步是实现一些不那么干净但更快的东西,比如System.Threading.ReaderWriterLockSlim。它的好处是,它允许所有线程同时读取,但在写入时阻止所有内容。所以本质上你只是在阻止一个写操作。
此外,在进行ToList
或ToArray
等时要注意参考类型
void Main()
{
var slist = new List<Chunk>();
var chunk = new Chunk{Name="asdf"};
slist.Add(chunk);
var slist2 = slist.ToList();
slist[0].Name = "asdf2";
Console.WriteLine(slist[0].Name); // outputs: asdf2
Console.WriteLine(slist2[0].Name); // outputs: asdf2
}
public class Chunk
{
public string Name {get;set;}
}