产生新线程的轻微延迟会导致竞争状况

时间:2014-02-17 20:14:22

标签: c# multithreading locking

我有一些在新线程中运行的初始化代码,需要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!

0 个答案:

没有答案