【问题标题】:c# lock on Array vs Index of Arrayc#lock on Array vs Index of Array
【发布时间】:2019-01-11 15:12:38
【问题描述】:

鉴于下面的代码

var array = new object[10];
for(int x = 0;x<array.Length;x++)
    array[x] = new object();


//Lock on Array
lock(array){
    //Do Stuff
}

//Lock on object of array
lock(array[1]){
    //Do Stuff
}

//lock on another object
var o = array[1];
lock(o){
    //Do Stuff
}

第一个 lock 语句将锁定对象 array

但是在第二个 lock 语句中,锁定是发生在数组索引 1 处的对象上,还是也发生在对象 array 上?另一种问问题的方式,第二把锁和第三把锁的行为是一样的吗?

【问题讨论】:

  • 做第二个锁,然后分别尝试第一个和第三个,看看哪个被阻止,哪个可以被占用。然后你就会知道哪个被锁定了。
  • 我认为这真的不值得一个完整的答案,所以在这里作为评论:第二个和第三个锁都锁定在同一个对象上:数组索引 1 处的对象。做什么服务建议。
  • array 索引 1 处有一个对象。在您的第三个示例中,您创建了一个附加的 变量 来引用同一个对象,但仍然只有一个对象同时 @ 987654325@ 和 array[1] 正在引用。
  • 你绝对不能,永远不要写这样的代码。它给人一种错误的印象,即数组现在处于一种使其成为线程安全的神奇状态。类似的事情实际上并没有发生。始终声明一个专用变量来存储锁定状态。几个优点,一个是你不必问这个问题。
  • 另一个优势(关于@HansPassant 的评论)是,当您创建像private object _myLock = new object(); 这样的私有变量时,您的班级之外的任何人都不能弄乱您用作锁的对象。始终为您的锁专用一个私有(非值类型)对象 - 它更安全、更清晰

标签: c# multithreading locking


【解决方案1】:

由于多线程的复杂性,我从不喜欢使用lock。回答我的问题,这里使用下面的代码是结果。

场景 2 和 3 是等效的。这些锁定语句相互干扰(这是通过查看代码所期望的)。

场景 1 不会干扰 2 或 3。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        public static object o;
        public static object[] array;

        static void Main(string[] args)
        {
            array = new object[10];

            for (int x = 0; x < array.Length; x++)
                array[x] = new object();

            o = array[1];
            var tasks = new Task[100];
            Task t;


            //t = Task.Run(() => lockArray(5000));
            t = Task.Run(() => lockArrayIndex(5000));
            //t = Task.Run(() => lockObject(5000));
            for (int i = 0; i < tasks.Length; i++)
            {
                //tasks[i] = Task.Run(() => lockArray(1000));
                //tasks[i] = Task.Run(() => lockArrayIndex(1000));
                tasks[i] = Task.Run(() => lockObject(1000));
            }



            Task.WaitAll(tasks);

            "done".Dump();
            Console.ReadKey();
        }

        private static void lockArray(int input)
        {
            //Lock on Array
            lock (array)
            {
                System.Threading.Thread.Sleep(input);
                "Array".Dump();
            }
        }

        private static void lockArrayIndex(int input)
        {
            //Lock on object of array
            lock (array[1])
            {
                System.Threading.Thread.Sleep(input);
                "Array[1]".Dump();
            }
        }

        private static void lockObject(int input)
        {
            //lock on another object
            lock (o)
            {
                System.Threading.Thread.Sleep(input);
                "o".Dump();
            }
        }
    }

    public static class extenstions
    {
        public static void Dump(this string input)
        {
            Console.WriteLine(input);
        }
    }
}

【讨论】:

  • Re,“我从不喜欢……多线程的复杂性。”是的,很难做到正确,但是您的多线程代码应该 (A) 比等效的单线程程序更容易阅读,或者 (B) 比等效的单线程程序更快程序,或 (C) 以上两者。如果您无法达到其中一个目标,那么线程可能不是解决问题的正确方法。
猜你喜欢
  • 2014-12-15
  • 1970-01-01
  • 2022-12-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 2022-12-01
  • 1970-01-01
相关资源
最近更新 更多