Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 平行。用于未正确处理锁_C#_Multithreading_Thread Safety - Fatal编程技术网

C# 平行。用于未正确处理锁

C# 平行。用于未正确处理锁,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,我做了以下测试: private static object threadLocker = new object(); private static long threadStaticVar; public static long ThreadStaticVar { get { lock (threadLocker) { return threadStaticVar; } } set

我做了以下测试:

private static object threadLocker = new object();

private static long threadStaticVar;
public static long ThreadStaticVar
{
    get
    {
        lock (threadLocker)
        {
            return threadStaticVar;
        }
    }
    set
    {
        lock (threadLocker)
        {
            threadStaticVar = value;
        }
    }
}

Parallel.For(0, 20000, (x) =>
{
    //lock (threadLocker) // works with this lock
    //{
        ThreadStaticVar++;
    //}
});
Parallel.For
调用将值从0传递到19999的方法。因此,它将执行20000次

如果我不包装
ThreadStaticVar++锁的code>,即使它的
get
set
上有锁,结果也不会是
20000
。如果我删除注释栏并将其锁定在
中。对于
,它将获得正确的值


我的问题是:它是如何工作的?为什么
get
set
上的锁不起作用?为什么它只在我的
For
中工作?

操作符
++
不是原子增量。将调用
get
,然后调用
set
,这些调用可以在不同的线程之间交错,因为锁只在每个单独的操作上。你可以这样想:

lock {tmp = var}
lock {var = tmp+1}

这些锁现在看起来不是很有效,是吗?

在您的示例中
ThreadStaricVar++
不是原子操作

更准确地说,
++
不是一个原子操作,因为它锁定getter,然后增加值,然后锁定setter来设置值。在这两者之间,任何事情都可能发生:)

为了正确地完成它,我建议使用面向对象编程,而不是使用此过程代码。只需在对象中实现一个
Increment()
方法,并让它负责在该方法中锁定和执行
++
。在您的并行循环中,您只需命令您的对象做什么,现在这个对象的责任就是让它发生并找出如何做


因此,您只需在Increment()方法中实现锁,在外部任何地方都没有问题(实际上,消费者不应该知道,甚至不应该考虑这些问题)。

您可以重命名
threadStaticVar
,并将其公开。然后,使用

但是,也要考虑并行是否合适。即使实际代码更复杂,与锁定并行运行也可能不是最佳选择