c#螺纹锁和监视器

c#螺纹锁和监视器,c#,multithreading,locking,monitor,C#,Multithreading,Locking,Monitor,我目前遇到了多线程和访问静态列表的问题。静态列表包含具有多个属性的所有项。项目由Guid标识。主工作线程更改静态列表中任何项的某些属性。子线程都有自己的Guid,通过这个Guid,它们在静态列表中读取自己的项。在一个特定的事件之后,他们从静态列表中删除他们分配的元素 为了找到源代码,我将代码分解为基本的方法和类。工作线程具有以下简化代码 public void RunWork() { Random random = new Random(); Int32 index = -1;

我目前遇到了多线程和访问静态列表的问题。静态列表包含具有多个属性的所有项。项目由
Guid
标识。主工作线程更改静态列表中任何项的某些属性。子线程都有自己的
Guid
,通过这个
Guid
,它们在静态列表中读取自己的项。在一个特定的事件之后,他们从静态列表中删除他们分配的元素

为了找到源代码,我将代码分解为基本的方法和类。工作线程具有以下简化代码

public void RunWork()
{
    Random random = new Random();
    Int32 index = -1;
    while (!Kill)
    {
        Thread.Sleep(1);
        if (MainWindow.Clients != null)
        {
            index = random.Next(0, MainWindow.Clients.Count);

            MainWindow.Clients[index].State = MainWindow.RandomString(9);
        }
    }
}
public void RunChild()
{
    Random random = new Random();
    while (!Kill)
    {
        Thread.Sleep(100);
        if (MainWindow.Clients.Any(x => x.Id == Id))
        {
            this.State = MainWindow.Clients.First(x => x.Id == Id).State;
        }
        Thread.Sleep(random.Next(50));
        if (random.Next(100) % 90 == 0)
        {
            Kill = true;
            MainWindow.Clients.RemoveAll(x => x.Id == Id);
        }
    }
}
每个子线程都有以下简化代码

public void RunWork()
{
    Random random = new Random();
    Int32 index = -1;
    while (!Kill)
    {
        Thread.Sleep(1);
        if (MainWindow.Clients != null)
        {
            index = random.Next(0, MainWindow.Clients.Count);

            MainWindow.Clients[index].State = MainWindow.RandomString(9);
        }
    }
}
public void RunChild()
{
    Random random = new Random();
    while (!Kill)
    {
        Thread.Sleep(100);
        if (MainWindow.Clients.Any(x => x.Id == Id))
        {
            this.State = MainWindow.Clients.First(x => x.Id == Id).State;
        }
        Thread.Sleep(random.Next(50));
        if (random.Next(100) % 90 == 0)
        {
            Kill = true;
            MainWindow.Clients.RemoveAll(x => x.Id == Id);
        }
    }
}
如果子线程从
main窗口.Clients
列表中删除自身,则工作线程会抛出一个异常,即它试图访问的索引不存在

我在
main窗口的每个访问位置添加了
lock
stations。客户端
,但这并不阻止工作线程访问已删除的项目。我还尝试了
Monitor.Enter(MainWindow.Clients)
Monitor.Exit(MainWindow.Clients)
,但结果与
lock
相同

静态列表
main窗口。客户端
在任何线程运行之前创建,永远不会重新创建或释放

如果在
RunWork()
方法中围绕此代码块设置了
lock
语句

lock (MainWindow.Clients)
{
    Thread.Sleep(1);
    if (MainWindow.Clients != null)
    {
        index = random.Next(0, MainWindow.Clients.Count);

        MainWindow.Clients[index].State = MainWindow.RandomString(9);
    }
}
为什么不阻止子线程更改行之间的列表 在何处设置随机索引并访问列表

更新1: 以下代码仍然在
MainWindow.Clients[index].State=MainWindow.RandomString(9)处抛出IndexOutOfRangeException

更新2:是快速示例应用程序的完整代码

更新3:我已经编辑了我的代码,并用lock语句包装了对
main window.Clients
的所有访问。但线程仍在锁定变量时访问该变量:

我不确定您到底想要实现什么,但我已经写了一些东西,可能会帮助您找到正确的解决方案。抱歉,时间安排不准确;-)

使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用系统诊断;
使用System.Linq;
使用系统线程;
命名空间ConcurrentCollectionTest
{
内部类客户端
{
公共字符串状态
{
获得;设置;
}
公共字符串名
{
收到
内集;
}
}
内部类主窗口
{
私有ConcurrentDictionary_dict=新ConcurrentDictionary();
公共词典客户端
{
收到
{
返回命令;
}
}
}
内部课程计划
{
私有静态bool killAll=false;
私有静态MainWindow MainWindow=新MainWindow();
私有静态int id=-100;
私有静态字符串状态=“初始”;
私有静态随机=新随机();
私有静态对象lockObject=新对象();
内部静态字符串随机字符串(int v)
{
int k=随机。下一个(0,v);
返回k.ToString();
}
公共静态void RunChild()
{
Debug.WriteLine($“运行{Thread.CurrentThread.Name}的子线程”);
bool killThis=false;
而(!killThis&!killAll)
{
睡眠(100);
Client=null;
if(mainWindow.Clients.TryGetValue(id,out-client))
{
state=client.state;
}
Thread.Sleep(random.Next(50));
if(随机下一个(100)%90==0)
{
WriteLine($“killing{Thread.CurrentThread.Name}”);
这是真的;
锁定(锁定对象)
{
主窗口。客户端。删除(id);
}
}
}
}
公共静态无效运行工作()
{
Console.WriteLine(“RunWork”);
随机=新随机();
Int32指数=-1;
而(!killAll)
{
如果(!mainWindow.Clients.Any())
{
基拉尔=真;
打破
}
睡眠(100);
//编辑:仍然需要在此处锁定,因为计数可以在其间更改
Client=null;
锁定(锁定对象)
{
index=random.Next(0,mainWindow.Clients.Count);
客户端=主窗口。客户端[索引];
}
Debug.WriteLine($“更改{client.Name}”);
client.State=RandomString(9);
}
控制台。WriteLine(“工人死亡”);
}
私有静态void Main(字符串[]args)
{
Console.WriteLine(“启动。输入id或kill”);
对于(int i=0;i<100;i++)
{
主窗口.客户端.添加(i,新客户端)
{
Name=$“客户端{i:000}”,
State=“未知”
});
}
var-worker=新线程(RunWork);
worker.Start();
var threadList=新列表();
threadList.Add(worker);
对于(int i=0;i<10;i++)
{
var thread=新线程(RunChild)
{
Name=$“子{i:00}”
};
线程列表。添加(线程);
thread.Start();
}
而(!killAll)
{
var str=Console.ReadLine();
如果(str.Equals