简体   繁体   English

在同时调用方法时是否需要同步访问方法参数和本地?

[英]Do I need to synchronize access the method arguments and locals when calling a method concurrently?

I have been writing a lot of code with static classes/methods that I believe will be called/executed simultaneously by multiple threads. 我一直在用静态类/方法编写很多代码,我认为这些代码将由多个线程同时调用/执行。 So I am doing a lot of locking in my methods. 所以我在我的方法中做了很多锁定。 I typically do this: 我通常这样做:

public static class MyThreadsafeMethods {

    private static Object staticLock1 = new Object();
    private static Object staticLock2 = new Object();

    public static string StaticMethod1(string param1, int param2) {
        lock (staticLock1) {
            var _param1 = param1;
            var _param2 = param2;

            //highly confidential business logic here

            return StaticMethod2(_param1, "Integer: " + _param2.ToString());
        }
    }

    public static string StaticMethod2(string param1, string param2) {
        lock (staticLock2) {
            var _param1 = param1;
            var _param2 = param2;

            //truly groundbreaking algorithm here

            return _param1 + " - " + _param2;
        }
    }
}

I am wondering two things: 我想知道两件事:

1) I have thought that I need to be working with local "copies" of my parameters inside the "locked code"; 1)我以为我需要在“锁定代码”中使用我的参数的本地“副本”; because if another thread calls my method with different values for param1 and param2, that could mess up my processing. 因为如果另一个线程用param1和param2的不同值调用我的方法,那可能会搞砸我的处理。 If I only work with variables that are declared/instantiated inside the locked code (ie _param1 and _param2 in the example above), then something could change the values of param1 and param2 (or send in references to different objects) and I am okay. 如果我只使用在锁定代码中声明/实例化的变量(即上例中的_param1和_param2),那么某些东西可以改变param1和param2的值(或者发送对不同对象的引用),我没关系。 But do I need to do that? 但我需要这样做吗? Am I being unnecessarily paranoid? 我是不必要的偏执狂?

2) I have decided that I don't want to instantiate my lock objects until I need them, because my collection of static locking objects is growing... So, I am now moving to doing this: 2)我已经决定在我需要它之前不想实例化我的锁对象,因为我的静态锁定对象集合正在增长......所以,我现在正在这样做:

    private static Object staticLock1;

    public static string StaticMethod1(string param1, int param2) {
        lock(staticLock1 = staticLock1 ?? new Object()) {
            (...)
        }
    }

Is there any reason that instantiating my lock object the first time I need it is unsafe? 是否有任何理由在我第一次需要时实例化我的锁定对象是不安全的? Will using the assignment operator on my lock object in my lock statement somehow cause me problems or prevent the object from being properly locked? 在我的锁定语句中使用我的锁定对象上的赋值运算符会不会导致我出现问题或阻止对象被正确锁定?

  1. What you have there won't make any difference at all - the arguments themselves cannot change after the call has been made, so it really does nothing. 你所拥有的东西根本没有任何区别 - 在调用之后,参数本身不会改变,所以它什么也没做。 In your case with strings, it's perfectly safe seeing how string is immutable. 在你的情况下使用字符串,看到字符串是不可变的是非常安全的。 When that isn't the case, it is possible that whatever is passed is altered somewhere else. 如果不是这种情况,则传递的任何内容都可能在其他地方被更改。 In that case you'd have to make a real copy (ie not just copying the reference), 在这种情况下,你必须制作一个真正的副本(即不只是复制参考),

  2. Consider the case where two threads arrive at lock(staticLock1 = staticLock1 ?? new Object()) at the same time. 考虑两个线程同时到达lock(staticLock1 = staticLock1 ?? new Object())的情况。 They could both see staticLock1 as null. 他们都可以将staticLock1视为null。 So no that's not safe! 所以没有那不安全!

Your main confusion seems to be around what synchronization you need in order to safely call a static method concurrently. 您的主要困惑似乎是为了安全地同时安全地调用静态方法所需的同步。

Data races always arise because multiple threads access the same storage location in an unsynchronized way, and at least one of them is a writer. 数据争用总是会出现,因为多个线程以不同步的方式访问同一个存储位置,并且其中至少有一个是编写器。 This basic rule is enough to reason about a lot of concurrency issues. 这个基本规则足以说明很多并发问题。

When you call a method, the arguments have different storage locations for each call. 调用方法时,参数对每个调用都有不同的存储位置。 They are independent. 他们是独立的。 Therefore, two threads calling the same method never race to access method arguments. 因此,调用相同方法的两个线程永远不会竞争访问方法参数。 You therefore never need to synchronize access to method arguments. 因此,您永远不需要同步对方法参数的访问。

The same goes for locals. 当地人也是如此。 In fact, arguments have identical synchronization properties as locals have. 实际上,参数具有与locals相同的同步属性。 They exist per call. 每次通话都存在。

To answer your second issue: That is unsafe because two threads might lock on different objects. 回答你的第二个问题:这是不安全的,因为两个线程可能会锁定不同的对象。 Also, you write to staticLock1 unsynchronized on multiple threads. 此外,您在多个线程上写入staticLock1同步。 I already explained that this is a data-race. 我已经解释过这是一场数据竞赛。

First: the overhead of creating an instance of Object is extremely small. 第一:创建Object实例的开销非常小。 Don't worry about it unless measurements show you that you should. 除非测量显示您应该这样做,否则不要担心。

Just initialize like this: 只需像这样初始化:

private readonly static object staticLock1 = new Object();

The way you use the lock statement is not safe. 你使用lock语句的方式并不安全。

Secondly: I see no shared data in the methods so there is no reason to lock. 其次:我在方法中看不到共享数据,所以没有理由锁定。

Finally: I would reconsider the design if it contains many static functions. 最后:如果设计包含许多静态函数,我会重新考虑它。

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

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