代码之家  ›  专栏  ›  技术社区  ›  AngryHacker

从不同的线程更新对象的不同属性是线程安全的吗?

  •  4
  • AngryHacker  · 技术社区  · 6 年前

    考虑下面的伪代码。我有一个具有3个属性的类,每个属性都是通过不同的方法并行填充的。

    从不同的线程填充同一类实例的不同属性会有问题吗?我设置了一个 .net fiddle

    如果这段代码会导致线程问题,我应该使用什么方法在填充属性时锁定响应类的特定实例?

    class Response {
        public string Response1 { get; set; }
        public string Response2 { get; set; }
        public string Response3 { get; set; }
    }
    
    void foo() {
        var response = new Response();
    
        var task1 = Task.Run(() => GetResponse1(response));
        var task2 = Task.Run(() => GetResponse2(response));
        var task3 = Task.Run(() => GetResponse3(response));
    
        Task.WaitAll(task1, task2, task3);        
    }
    
    void GetResponse1(Response response) {
        response.Response1 = fetchSomeValue1();
    }
    
    void GetResponse2(Response response) {
        response.Response2 = fetchSomeValue2();
    }
    
    void GetResponse3(Response response) {
        response.Response3 = fetchSomeValue3();
    }
    
    2 回复  |  直到 6 年前
        1
  •  4
  •   Matt Johnson-Pint    6 年前

    因为类只有一个实例(在 response 局部变量),则在类级别没有要锁定的内容。在 响应 变量,但这只是一个 到堆内存中的实例-而不是对象本身。

    此代码 是线程安全的。

    然而 ,如果有多个任务更新 相同的 在可能的同时 要保证线程安全,就必须实现锁定机制或将数据存储在固有的线程安全对象(例如 ConcurrentDictionary

        2
  •  2
  •   Stanisalv Dontsov    6 年前

    我建议你走这边:

    var response = Task<Response>
                        .Factory
                        .ContinueWhenAll(new Task<string>[]{task1, task2, task3},
                                                tasks => new Response {
                                                                        Response1 = tasks[0].Result, 
                                                                        Response2 = tasks[1].Result, 
                                                                        Response3 = tasks[2].Result
                                                                        })
                        .Result;
    

    https://dotnetfiddle.net/LHUa6G