我有一些在新线程中运行的初始化代码,需要4-5秒才能运行:
public virtual void Initialize()
{
Adapter.Initialize(this);
new Thread(delegate()
{
using (InitLock.WriteLock()) // <-- InitLock is a ReaderWriterLockSlim
{
ingParser = new IngredientParser();
var ingredientIndex = Adapter.LoadIngredientsForIndex();
ingParser.CreateIndex(ingredientIndex);
modeler = new ModelerProxy(this);
modeler.LoadSnapshot();
parser = new Parser();
LoadTemplates();
}
}).Start();
}
我还有几种方法利用在该线程中初始化的对象,但是它们使用相同的ReaderWriterLockSlim
对象,因此如果所需的对象尚未初始化,它们将阻塞:
public virtual Parser Parser
{
get
{
using (InitLock.ReadLock())
{
return parser;
}
}
}
现在,如果我运行此代码:
context.Initialize(); // Calls Initialize method above
// Do some other stuff that takes a bit of time
context.Parser.Parse("blah blah");
然后,一切正常。但是,如果我运行此代码:
context.Initialize(); // Calls Initialize method above
context.Parser.Parse("blah blah"); // Immediately call Parser
然后我在parser
上得到一个空引用异常。换句话说,我的初始化代码尚未运行,和 WriteLock
尚未建立,因此它不会阻止该线程。
我已经追溯到这样一个事实:在.NET中创建一个新线程时,有一个非常轻微的非阻塞延迟。如果我添加此代码:
}
}).Start();
Thread.Sleep(500); // Provides time for initialize thread to start and acquire InitLock
睡了半秒钟,一切都很好。
我的问题:我认为Sleep
电话很麻烦,并且在不同的系统上容易出现不同的行为。是否有更好的设计要等到在离开主线程之前在新线程上获取锁定?我可以在第一个线程中获取写锁并在第二个线程中处理它,但这似乎甚至更多 hacky!