c#锁定数组与数组索引

c#锁定数组与数组索引,c#,multithreading,locking,C#,Multithreading,Locking,根据下面的代码 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[

根据下面的代码

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
}
var数组=新对象[10];

对于(int x=0;x我从来都不喜欢使用
lock
,因为多线程的复杂性

Scenrio 2和Scenrio 3是等价的。这些lock语句相互干扰(这是通过查看代码可以预期的)

场景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);
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
班级计划
{
公共静态对象o;
公共静态对象[]数组;
静态void Main(字符串[]参数)
{
数组=新对象[10];
for(int x=0;xlockArray(5000));
t=Task.Run(()=>lockarayindex(5000));
//t=Task.Run(()=>lockObject(5000));
for(int i=0;ilockArray(1000));
//tasks[i]=Task.Run(()=>lockarayindex(1000));
tasks[i]=Task.Run(()=>lockObject(1000));
}
Task.WaitAll(任务);
“完成”。转储();
Console.ReadKey();
}
专用静态void锁数组(int输入)
{
//锁定阵列
锁(数组)
{
系统。线程。线程。睡眠(输入);
“Array.Dump();
}
}
私有静态void lockarayindex(int输入)
{
//锁定数组的对象
锁(数组[1])
{
系统。线程。线程。睡眠(输入);
“数组[1]”。Dump();
}
}
私有静态void锁对象(int输入)
{
//锁定另一个对象
锁(o)
{
系统。线程。线程。睡眠(输入);
“o”。Dump();
}
}
}
公共静态类扩展
{
公共静态无效转储(此字符串输入)
{
控制台写入线(输入);
}
}
}

进行第二次锁定,然后分别尝试第一次和第三次锁定,看看哪些被阻止,哪些可以被捕获。然后你就会知道哪个被锁定。我认为这不值得给出完整的答案,所以这里是一个注释:第二次和第三次锁定都锁定在同一个对象上:数组索引1处的对象。按照Servy的建议执行。在索引1的
数组中有一个对象。在第三个示例中,您创建了一个引用同一对象的附加变量,但仍然只有一个对象同时包含
o
数组[1]
正在引用。您决不能,决不能编写这样的代码。这会造成错误的印象,认为数组现在处于一种神奇的状态,使其线程安全。实际上不会发生这种情况。始终声明一个专用变量来存储锁状态。几个优点之一是您不必问这个问题。另一个优点是ntage(re@HansPassant的评论)是,当你创建一个私有变量,如
私有对象_myLock=new object();
,你的类外的任何人都不能弄乱你用作锁的对象。始终为你的锁指定一个私有(非值类型)对象-这样更安全、更清晰,“我从来都不喜欢……多线程的复杂性。”是的,很难做到正确,但是你的多线程代码应该(A)比同等的单线程程序更容易阅读,或者(B)比同等的单线程程序更快,或者(C)如果你不能达到其中一个目标,那么线程可能不是解决问题的正确方法。