如果我有两个共享资源,则这些资源将在并发运行的各自独立任务中进行更新。第二个任务从第一个任务检查共享资源的状态,然后更新它自己的共享资源。一项任务完成后,我然后检查两个共享资源的状态。我需要两个单独的锁来使该线程安全还是足够?例如:
private void example()
{
object lockObj = new object();
int x = 0;
int y =0;
List<Task> tasks = new List<Task>();
Task task1 = Task.Factory.StartNew(() =>
{
try
{
int z = doComputation()
resultofComputation = z;
}
catch
{
resultofComputation=-1;
}
finally
{
lock(lockObj)
{
x = resultofComputation;
}
}
}
tasks.Add(workTask);
Task task2 = Task.Factory.StartNew(() =>
{
try
{
checkOnstatusofThing(ref x);
lock(lockObj)
{
y +=x;
}
}
finally
{
}
}
Task.WaitAny(tasks.ToArray());
if(x =3 || y ==9)
{
return -1;
}
return 0;
}
checkOnstatusofThing(ref int x)
{
if(x == 5)
{
return;
}
}
答案 0 :(得分:1)
使用单个锁对象是安全的选择。您定义包含共享状态的变量,并在每次从 any 线程写入和读取这些变量时,仔细使用锁每次。如果这样做,那么将很容易证明应用程序的正确性(通过多线程标准容易实现,这本来就很困难)。
要最大程度地减少对锁的争用,应尽快释放它。持有锁时,应避免执行与共享状态无关的任何操作。例如,如果您必须调用一个以共享变量作为参数的方法,请对该变量进行快照,然后将该快照用作参数。
int snapshot;
lock (lockObj)
{
snapshot = sharedState;
}
MethodCall(snapshot);
如果您遵循此建议,则锁的争用应该最少,并且不会显着影响应用程序的性能。但是,如果您的基准测试表明该锁存在太多争用,那么您可以考虑引入多个锁以增加锁定方案的粒度并减少争用。请注意,此更改将在一定程度上增加应用程序的复杂性。死锁将成为可能,因此您必须熟悉Five Dining philosophers之类的经典同步问题及其解决方案。