如何正确锁定Task.Run()块

时间:2019-06-07 09:03:15

标签: c# locking task

我正在编写一个应用程序,在其中我使用几种访问某些共享资源的方法,因此通过lock(thisLock){ [...] ]来实现一些安全性

一切都很好,直到我不得不在异步任务中使用资源为止。 这是代码:

private object thisLock = new object();
[...]
private void UpdateStuff()
{
lock(thisLock)
   {
     Task.Run(()=>{[code where I use shared resources]});
   }
}

它似乎工作正常,但我想知道这是否是正确的方法,还是应该将lock()部分放在Run()内,如下所示:

private void UpdateStuff()
{

     Task.Run( () => {
        lock(thisLock)
        {
         [code where I use shared resources]
        }
     });    
}

我试图获得一些信息,但是我发现的所有内容都提到了使用关键字async时的情况,而事实并非如此。

所以,我的问题是:哪一种是对Task.Run()使用lock()的最佳/正确方法?为什么?

谢谢!

编辑:为了澄清起见,我的疑问是锁定何时有效以及锁定多少,所以基本上我问的是,在第一种情况下,是否有可能仅针对Run()使用锁定?调用,因为调用本身的内容可能存在于另一个线程中,而在第二种情况下,锁将与该内容相关联,因此是有效的。

2 个答案:

答案 0 :(得分:3)

您的第一种方法是完全错误的。 Task.Run可以在同一线程上同步执行工作或将其排队到线程池中。您不知道会发生什么。

您不是在等待任务完成,因此,如果将其排队到线程池中,则您的函数可能会在工作开始之前释放锁并返回。

通常,最佳实践是仅在需要的时间内获取锁,并且在等待另一个线程时不要保持锁,因为如果您不太谨慎的话,很容易导致死锁。

答案 1 :(得分:1)

这两者之间没有最好的方法,您只会获得两种不同的结果:

在第一种情况下,直到打开锁,您才开始任务。

在第二种情况下,您将启动一个任务,直到打开锁,该任务才做任何事情。

在我看来,直到需要时才打开任务是一种更好的方法,但这只是个人观点。打开并锁定之后,将分配无用的资源。