以下代码给了我一个例外:
var snapshot = BluetoothCapture.Instance.Snapshot();
var allowedDevice = snapshot.FirstOrDefault( _ => some_expression );
收藏被修改;枚举操作可能无法执行。
我以为我可以使用 lock 来冻结集合,以便我可以遍历它。但是,我仍然得到同样的例外。
下面的类定义有一个 Snapshot 方法,可以尝试这个:
public partial class BluetoothCapture
{
...
public void Capture()
{
_watcher = DeviceInformation.CreateWatcher();
_watcher.Added += (s, e) => { _devices.Add(e); };
_watcher.Start();
}
public IEnumerable<DeviceInformation> Snapshot()
{
lock (_devices)
{
return _devices.AsReadOnly();
}
}
}
有什么建议吗?
答案 0 :(得分:0)
当您需要停止在多个线程中执行的代码块(停止并行执行)时,使用锁定。 如果多次调用Capture,那么,是的,您可以在前一个完成之前调用write。
您可以使用ConcurrentBag。 ConcurrentBag是一个类似于对象的列表,但它是线程安全的(没有通用列表)。 但是,ConcurrentBag是无序集合,因此它不保证订购。
如果您需要一些有序列表,可以看到此链接 Thread safe collections in .NET
你也可以做一个&#34;锁定&#34;在添加(不在获取)
_watcher.Added += (s, e) => { lock(_devices){_devices.Add(e); }};
但是,如果您的应用程序运行一段时间,您可能会遇到内存和性能问题(添加将不是异步),即使Capture是。
答案 1 :(得分:0)
lock
是非常有用的概念,但只有在我们明智地使用它时才会这样。
如果在进一步的代码中,您不想更新snapshot
(您从BluetoothCapture.Instance.Snapshot()
获得的集合)的引用,只需执行一些Linq
查询即可获取过滤值以执行某些逻辑。
您可以避免使用lock
。
这也是有益的,因为没有做lock
你实际上没有持有其他线程来执行它的逻辑。 - 我们不应忽视这样一个事实,即lock
的可怕使用也会导致dead-lock
等严重问题。
您正在获得此异常,最有可能的是您正在执行linq
查询的集合;正在由其他一些线程更新。 (我也遇到了这个问题)。
你可以做一件事,而不是使用集合的一般引用(你从BluetoothCapture.Instance.Snapshot()
得到的那个),你可以创建一个本地列表 - 因为它是本地的,它不会被其他线程更新。