【问题标题】:Looking for advice on thread safety using static methods to 'process' a class instance寻找有关使用静态方法“处理”类实例的线程安全的建议
【发布时间】:2011-06-29 23:05:47
【问题描述】:

我最近继承了一个系统,它使用一种非常基本的方法来处理工作项,基本上,它会一个一个地处理它们。老实说,直到最近这还不错。但是,我们正在寻求为另一种类型的工作项实施类似的流程,我一直在研究任务并行库,并认为这符合要求。但是,我对线程安全有些担忧,老实说,这是我缺乏知识的领域,所以我在这里只问我的第二个问题,希望有人能给我一些好处,因为我还没有找到确定是或否的答案。

所以我们有了“WorkItem”类

public class WorkItem
{
    public int Id {get; set;}
    public string data { get; set;}
}

将生成一个List<WorkItem>,然后使用Parallel.Foreach 循环对其进行处理。

Parallel.Foreach 将调用一个私有方法,而该私有方法又会调用另一个程序集的静态方法;

//Windows service that will run the Parallel.Foreach
private int MainMethod(WorkItem item) 
{
    item.Data = Processor.ProcessWorkItemDataProcess1(item.data);
    item.Data = Processor.ProcessWorkItemDataProcess2(item.data);
    SendToWorkFlow(item);
}


public static class Processor
{
    public static string ProcessWorkItemDataProcess1(string data)
    {
    //Process it here
    return string
    }

    public static string ProcessWorkItemDataProcess2(string data)
    {
        //Process it here
        return string
    }
}

等等。所有这些方法都包含在各个不同阶段处理 WorkItem 实例的逻辑。完成后,MainMethod 会将处理后的 WorkItem 发送到工作流系统。

我们将分批处理最多 30 个,以免其他系统过载。我的担忧基本上是 30 个 WorkItem 实例访问相同的静态方法可能会导致一些数据完整性问题。例如,ProcessWorkItemDataProcess2WorkItem1.Data 调用,随后用WorkItem2.Data 调用,不知何故,WorkItem2.Data 在它应该是WorkItem1.Data 时返回

所有静态方法都是自包含的,只要它们定义了逻辑并且只会(理论上)使用调用它的WorkItem。没有DB访问、文件访问等方法。

所以,希望这能解释我在做什么。我应该有什么顾虑吗?如果是这样,为每个 WorkItem 创建一个 Processor 类的实例会解决任何潜在问题吗?

提前致谢

【问题讨论】:

  • 对我来说听起来相当安全,但对于并发代码,魔鬼总是在细节中。如果不仔细检查您正在谈论的确切代码,任何人都不可能给出任何明确的建议。
  • 你会寻找什么样的东西?

标签: c# multithreading class static


【解决方案1】:

您描述的场景听起来没有任何明显的线程问题。您担心在两个不同的线程上调用静态方法并混淆数据是没有根据的,除非您编写代码来混淆。 ;>

由于方法是静态的,它们不需要担心任何共享对象实例。那挺好的。您已将工作隔离为独立的工作项。这很好。

您需要检查以确保没有任何静态方法访问任何全局状态,例如静态变量或属性,或从文件读取(多个工作项的文件名相同)。全局状态的读取不那么重要,而写入才是工作中的关键。

您还应该查看您的代码,以了解如何将数据分配给您的工作项,以及处理工作项的任何代码是否修改了工作项数据。如果工作项被方法严格地视为只读,那很好。如果方法将更改写回工作项的字段或属性,您将需要仔细检查工作项中的数据是否未与任何其他工作项共享。如果构造工作项实例的代码将缓存值分配给多个工作项的属性,并且静态方法修改该值的属性,您将遇到线程冲突。如果工作项构造总是构造分配给工作项属性的值的新实例,这应该不是问题。

【讨论】:

    【解决方案2】:

    简而言之,如果您有多个线程访问共享状态,并且至少有一个正在写入,那么您需要担心线程安全。如果不是,那你就是金子。

    【讨论】:

    • 抱歉,您能否定义“共享状态”。每个静态方法都会从 WorkItem 传递数据并返回它。
    • 您的经典状态示例是变量。当 2 个线程同时访问时,它变为共享。
    • 这是在处理器中声明的静态变量,还是在静态方法本身中的私有变量?
    • @Chris 方法中的变量,也就是局部变量,在方法的调用之间不共享。您通常不需要仔细检查局部变量来确定方法的线程安全性,除非您为这些变量创建闭包。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多