C#锁定和一般螺纹设计问题

C#锁定和一般螺纹设计问题,c#,multithreading,locking,C#,Multithreading,Locking,我有一个线程控制台应用程序,工作正常,但它的架构需要改进,我希望得到一些反馈 当前,程序加载一个数据列表,并将该数据分段到分区中(每个线程一个块)。然后,程序使用线程池初始化一个新线程,并向其传递一段要操作的分区数据 一切都很好…除了: 由于网络问题或不可恢复的异常,某些线程失败。这是预期的行为,而不是bug 我现在需要一种方法(如果线程失败)来恢复该线程的数据段,并将其提供给另一个工作线程,以便它不会成为孤立线程。我确信有办法做到这一点,即在线程之间共享数据,等等,但我认为有更好的方法 我可以

我有一个线程控制台应用程序,工作正常,但它的架构需要改进,我希望得到一些反馈

当前,程序加载一个数据列表,并将该数据分段到分区中(每个线程一个块)。然后,程序使用线程池初始化一个新线程,并向其传递一段要操作的分区数据

一切都很好…除了:

由于网络问题或不可恢复的异常,某些线程失败。这是预期的行为,而不是bug

我现在需要一种方法(如果线程失败)来恢复该线程的数据段,并将其提供给另一个工作线程,以便它不会成为孤立线程。我确信有办法做到这一点,即在线程之间共享数据,等等,但我认为有更好的方法

我可以在所有线程之间共享此数据的一个静态集合,而不是预先分割数据并将其传递给每个线程。这更优雅,但引入了新发现的同步问题,而旧方法不必担心这些问题

A.)与旧方法相比,您对这种方法有何看法?
B.)如果这种方法很好,那么如何锁定对共享静态集合的访问

当线程初始化时,我可以锁定集合并弹出该线程的一段数据。静态收集现在将减少该线程弹出的数量。当线程失败时,我可以通过再次锁定该数据段,并将数据推回到集合中,以便其他线程尝试处理,从而将该数据段重新分配到共享集合中

例如:(未测试的伪代码)


我做得对吗?在我看来,一个线程可以在另一个线程重新分配项目的同时删除项目……或者静态集合上的锁意味着没有其他线程可以访问该集合。因此,线程A.)在方法的第一部分中获得了一个锁,这会阻止所有其他线程执行方法的最后一部分,直到线程A完成吗?

让我们在这里分开几件事

首先,您实际上并没有锁定收藏。您正在锁定与对象关联的监视器。我个人认为.NET跟随Java给每个对象一个关联的监视器来锁定是一个错误,但让我们把它放在一边。就个人而言,我更喜欢对象和关联变量纯粹用于锁定-因此在我的代码中,您可能会看到:

private readonly object padlock = new object();
这确保没有其他代码试图获取该锁,因为它们不知道该对象

其次,锁是建议性的。这是“您没有锁定集合”业务的一部分。如果集合本身在同一个锁上同步-并且非泛型集合为此目的有一个
Synchronized
方法-但基本上,除非某个地方明确地取出锁,否则您将无法获得同步

第三,是的,代码中显示的两个锁定块使用相同的锁(当然,假设
StaticCollection
的值不变)。如果一个线程正忙于调用
Remove
,这将阻止任何其他线程同时调用
Add
,因为它们都需要锁。那可能是你想要的


不过,我个人不会让它成为真正的静态集合(或者更确切地说,我不会使用
StaticCollection
变量)。我会给每个任务一个对同一集合的引用(以及对关联锁的引用;事实上,我可能会将集合、同步和“给我一堆工作”和“这里有一堆工作要做”位封装在一个单独的类中)。这将使测试变得更简单,逻辑上也更准确。这也意味着您可以同时在不同的集合上有两个单独的线程“集合”。。。如果你使上面的封装通用,那么它们可以执行根本不同的任务……

,你可以考虑使用队列来保存未处理的块,正如Jon Skeet所说,锁定一个中立对象,并且只保存足够长的锁来访问队列。我已经用很多线程使用了这个方法,它对我来说很好。

你的解决方案其实很好(除了取和删除调用,你可能想考虑使用一个实际的堆栈)。我喜欢您提供的解决方案,因为它还允许您将发生故障的对象推回到堆栈或队列中,而不需要其他集合来跟踪每个项目的处理状态。现在有人可能会尖叫为什么这是可怕的…操作需要作为单个事务成功还是失败?(该过程是否会改变其运行的数据段中的数据?)
private readonly object padlock = new object();