是否有两个对象的两个锁?

时间:2020-07-14 16:36:09

标签: c# thread-safety locking

如果我有两个共享资源,则这些资源将在并发运行的各自独立任务中进行更新。第二个任务从第一个任务检查共享资源的状态,然后更新它自己的共享资源。一项任务完成后,我然后检查两个共享资源的状态。我需要两个单独的锁来使该线程安全还是足够?例如:

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;
    }
}

1 个答案:

答案 0 :(得分:1)

使用单个锁对象是安全的选择。您定义包含共享状态的变量,并在每次从 any 线程写入和读取这些变量时,仔细使用锁每次。如果这样做,那么将很容易证明应用程序的正确性(通过多线程标准容易实现,这本来就很困难)。

要最大程度地减少对锁的争用,应尽快释放它。持有锁时,应避免执行与共享状态无关的任何操作。例如,如果您必须调用一个以共享变量作为参数的方法,请对该变量进行快照,然后将该快照用作参数。

int snapshot;
lock (lockObj)
{
    snapshot = sharedState;
}
MethodCall(snapshot);

如果您遵循此建议,则锁的争用应该最少,并且不会显着影响应用程序的性能。但是,如果您的基准测试表明该锁存在太多争用,那么您可以考虑引入多个锁以增加锁定方案的粒度并减少争用。请注意,此更改将在一定程度上增加应用程序的复杂性。死锁将成为可能,因此您必须熟悉Five Dining philosophers之类的经典同步问题及其解决方案。

相关问题