简体   繁体   English

当有封闭时我是否需要使用互锁?

[英]Do I need to use interlocked when there is a closure?

Consider this piece of code that creates a closure around counter : 考虑这段代码在counter周围创建一个闭包:

uint counter = 0xFFFF;
someList.AsParallel().ForEach(a => { uint tmp = ++counter });

(Please set aside for a moment the obvious problem of using a counter within a parallel foreach). (请暂时搁置在并行foreach中使用计数器的明显问题)。

Will tmp ever evaluate to 0x0000 or 0x1FFFF? tmp会评估为0x0000还是0x1FFFF?

My reasoning: To increment counter from 0xFFFF to 0x10000 requires at least a two-byte CPU instruction that could be interrupted by multithreading. 我的理由:要将counter从0xFFFF递增到0x10000,至少需要一个可被多线程中断的双字节CPU指令。 If it gets interrupted, there is a chance that only one byte of counter will be updated -- it could temporarily be set to 0x00000 or 0x1FFFF. 如果它被中断,则有可能只更新一个字节的counter - 它可以暂时设置为0x00000或0x1FFFF。

Should I have written this as: 我应该把它写成:

uint counter = 0xFFFF;
someList.AsParallel().ForEach(a => { uint tmp = Interlocked.Increment(counter) });

...? ...?

And if I get rid of AsParallel , am I completely safe? 如果我摆脱AsParallel ,我完全安全吗?

Yes, you need Interlocked.Increment , closure doesn't change the fact that this operation isn't thread safe. 是的,你需要Interlocked.Increment ,闭包不会改变这个操作不是线程安全的事实。 What closure will do is lift you lambda expression into a display class and re-use that same class each iteration which will cause multiple threads incrementing the counter. 什么闭包将把你的lambda表达式提升到一个显示类中,并在每次迭代时重复使用相同的类,这将导致多个线程递增计数器。

Decompiling looks like this: 反编译看起来像这样:

public class C
{
    [CompilerGenerated]
    private sealed class <>c__DisplayClass0_0
    {
        public uint counter;
        internal void <M>b__0(int a)
        {
            uint num = this.counter + 1u;
            this.counter = num;
        }
    }
    public void M()
    {
        C.<>c__DisplayClass0_0 <>c__DisplayClass0_ = new C.<>c__DisplayClass0_0();
        <>c__DisplayClass0_.counter = 65535u;
        List<int> source = new List<int> {
            1,
            2,
            3
        };
        source.AsParallel<int>().ForAll(new Action<int>(<>c__DisplayClass0_.<M>b__0));
    }
}

And if I get rid of AsParallel , am I completely safe? 如果我摆脱AsParallel ,我完全安全吗?

As long as the list or counter aren't mutated while you're iterating, you should be ok. 只要在迭代时列表或计数器没有变异,你应该没问题。 From you example it isn't possible to know the actual locality of the data you're working with, but assuming everything is method scope local, you'll be fine. 从您的示例中,您无法知道您正在使用的数据的实际位置,但假设一切都是方法范围本地,您会没事的。

Yup. 对。 Parallel is just syntactic sugar for multi-threading. Parallel是多线程的语法糖。 You still need to be thread-safe. 你仍然需要线程安全。 If you are single threaded, you obviously don't need Interlocked (or to be thread safe). 如果你是单线程,你显然不需要Interlocked(或线程安全)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM