如何正确锁定集合
How to properly lock a collection
我一直在努力思考锁的问题,但我似乎无法弄清楚。
下面的代码使用了锁,但仍然给出 'collection was modified' 错误。我错过了什么?
class Program
{
static List<int> lEntries = new List<int>();
static readonly object entriesLock = new object();
public static List<int> Entries {
get { lock (entriesLock) { return lEntries; } }
set { lock (entriesLock) { lEntries = value; } }
}
static void Main(string[] args)
{
// Run 20 times to reproduce the issue more often
for (int i = 0; i < 20; i++)
{
Task.Run(() =>
{
for (int j = 0; j < 10000; j++)
{
Entries.Add(j);
}
});
Task.Run(() =>
{
for (int i = 0; i < 1000; i++)
{
Entries.Average(); // System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
}
});
}
Console.ReadLine();
}
}
锁仅在其范围内有效。
lock (entriesLock)
{
//safe to access here.
}
// no longer safe
因此,不幸的是,您尝试返回锁定列表是没有意义的,因为当 getter/setter 离开时锁定会立即过期。实际访问列表时使用外面的锁。
for (int j = 0; j < 10000; j++)
{
lock (entriesLock)
{
lEntries.Add(j);
}
}
// or
lock (entriesLock)
{
for (int j = 0; j < 10000; j++)
{
lEntries.Add(j);
}
}
我一直在努力思考锁的问题,但我似乎无法弄清楚。 下面的代码使用了锁,但仍然给出 'collection was modified' 错误。我错过了什么?
class Program
{
static List<int> lEntries = new List<int>();
static readonly object entriesLock = new object();
public static List<int> Entries {
get { lock (entriesLock) { return lEntries; } }
set { lock (entriesLock) { lEntries = value; } }
}
static void Main(string[] args)
{
// Run 20 times to reproduce the issue more often
for (int i = 0; i < 20; i++)
{
Task.Run(() =>
{
for (int j = 0; j < 10000; j++)
{
Entries.Add(j);
}
});
Task.Run(() =>
{
for (int i = 0; i < 1000; i++)
{
Entries.Average(); // System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'
}
});
}
Console.ReadLine();
}
}
锁仅在其范围内有效。
lock (entriesLock)
{
//safe to access here.
}
// no longer safe
因此,不幸的是,您尝试返回锁定列表是没有意义的,因为当 getter/setter 离开时锁定会立即过期。实际访问列表时使用外面的锁。
for (int j = 0; j < 10000; j++)
{
lock (entriesLock)
{
lEntries.Add(j);
}
}
// or
lock (entriesLock)
{
for (int j = 0; j < 10000; j++)
{
lEntries.Add(j);
}
}