在 C# 中访问多线程列表时的竞争条件
Race condition in accessing a list of mutliple threads in C#
private FruitResult GetFruitResult(Fruits fruits)
{
List<Thread> threads = new List<Thread>();
foreach (string fruit in fruits)
{
Thread t = new Thread(() => CheckFruitQuality(fruit, someOtherThings, ref fruitResult));
threads.Add(t);
}
threads.ForEach(x => x.Start());
threads.ForEach(x => x.Join());
return fruitResult;
}
private void CheckFruitQuality(string fruit, SomeOtherThings someOtherThings, ref FruitResult fruitResult)
{
......
get size and color
......
Result r = new Result();
r.Size = size;
r.Color = color;
fruitResult.FruitReports.Add(r);
}
由于 Thread 构造函数只接受委托,因此我不得不 return fruitResult 作为参考。现在,如何锁定 fruitResult,这样就不会出现竞争条件?
您应该尽可能避免在线程之间共享状态。锁定会降低性能和可伸缩性。手动创建线程也不是最佳实践。创建线程的成本非常高,您的 CPU 只能同时处理有限数量的线程。最好让线程池为你管理线程。使用 ref
参数使代码的可读性低于简单地从方法返回值。
所有这 3 个问题都可以通过使用 tasks 而不是线程来解决。然后你可以很容易地在不使用 ref
参数的情况下取回结果。如果 CheckFruitQuality
是计算密集型操作,您可以尝试这样的操作:
private async Task<FruitResult> GetFruitResult(IEnumerable<string> fruits)
{
var fruitResult = new FruitResult();
// start the tasks
var tasks = fruits.Select(fruit => Task.Run(() => CheckFruitQuality(fruit, someOtherThings)));
// wait for them to complete
var results = await Task.WhenAll(tasks);
//process results
foreach (var result in results)
{
fruitResult.FruitReports.Add(result);
}
return fruitResult;
}
private Result CheckFruitQuality(string fruit, SomeOtherThings someOtherThings)
{
// get size and color
return new Result()
{
Size = size,
Color = color
};
}
如果 CheckFruitQuality
是一个 I/O 操作,那么您可能甚至不需要并行性,只需使用异步 I/O。
任务在线程池线程上执行,因此比手动创建新线程效率更高。
private FruitResult GetFruitResult(Fruits fruits)
{
List<Thread> threads = new List<Thread>();
foreach (string fruit in fruits)
{
Thread t = new Thread(() => CheckFruitQuality(fruit, someOtherThings, ref fruitResult));
threads.Add(t);
}
threads.ForEach(x => x.Start());
threads.ForEach(x => x.Join());
return fruitResult;
}
private void CheckFruitQuality(string fruit, SomeOtherThings someOtherThings, ref FruitResult fruitResult)
{
......
get size and color
......
Result r = new Result();
r.Size = size;
r.Color = color;
fruitResult.FruitReports.Add(r);
}
由于 Thread 构造函数只接受委托,因此我不得不 return fruitResult 作为参考。现在,如何锁定 fruitResult,这样就不会出现竞争条件?
您应该尽可能避免在线程之间共享状态。锁定会降低性能和可伸缩性。手动创建线程也不是最佳实践。创建线程的成本非常高,您的 CPU 只能同时处理有限数量的线程。最好让线程池为你管理线程。使用 ref
参数使代码的可读性低于简单地从方法返回值。
所有这 3 个问题都可以通过使用 tasks 而不是线程来解决。然后你可以很容易地在不使用 ref
参数的情况下取回结果。如果 CheckFruitQuality
是计算密集型操作,您可以尝试这样的操作:
private async Task<FruitResult> GetFruitResult(IEnumerable<string> fruits)
{
var fruitResult = new FruitResult();
// start the tasks
var tasks = fruits.Select(fruit => Task.Run(() => CheckFruitQuality(fruit, someOtherThings)));
// wait for them to complete
var results = await Task.WhenAll(tasks);
//process results
foreach (var result in results)
{
fruitResult.FruitReports.Add(result);
}
return fruitResult;
}
private Result CheckFruitQuality(string fruit, SomeOtherThings someOtherThings)
{
// get size and color
return new Result()
{
Size = size,
Color = color
};
}
如果 CheckFruitQuality
是一个 I/O 操作,那么您可能甚至不需要并行性,只需使用异步 I/O。
任务在线程池线程上执行,因此比手动创建新线程效率更高。