3

我有一个在大多数情况下需要线程的应用程序。大多数时候我会遇到错误或错误值,因为对象在每个线程执行之前已更新。

您对如何使对象成为线程安全并确保对象对每个线程都具有正确性有什么建议吗?我应该做我的变量static吗?

4

3 回答 3

20

您应该做的第一件事是绘制要通过多线程解决的问题的Happens-Before 图。如果你不能画出你的设计,那就太复杂了。

例如,这是一个方法的发生前图,它采用两个整数数组并输出所有元素的总和。

在此处输入图像描述

一旦你有了之前发生的图表,就很容易看到在其他事情之前必须发生的事情,但更重要的是,它向你展示了在其他事情之前不需要发生的事情。

在此示例中,您可以同时获得 array1 和 array2 的总和。您也可以同时获得 sum1 和 sum2,因为它们不相互依赖。将总和添加到 TotalSum1 可以按任一顺序完成,(但您需要锁定加法步骤,因为您不能与另一个同时进行加法)。

C# .net 4.0 为并行编程提供了很多有用的功能。

我推荐这本书Parallel Programming with Microsoft .Net —— 只需使用左侧的书签进行导航。它涵盖了循环、任务、聚合、期货和管道的并行模式。

在上面的示例中,我将使用 Task1 来获取 Array1 和 Task2 来获取 Array2,然后在这两者中,我将使用内置到 Parallel.For 循环中的聚合模式来获取数组总和,我需要使用锁或 Interlocked.Add 以累积 subTotals,然后等待任务完成并返回结果。

有用的模式:

  • 任务
  • 并行循环
  • 生产者/消费者
  • 管道
  • 工作清单
  • MapReduce

有用的工具:

  • 任务并行库
    • 并行.For
    • Parallel.Foreach,
    • 任务
  • PLinq
  • 并发数据结构
    • 并发队列
    • 等等
  • 锁定
    • “锁定”关键字
    • 监视器(与“锁定”功能相同)
    • 信号量
    • 自旋锁
    • 读/写锁
  • 硬件原子操作
    • 互锁增量
    • 互锁。添加
    • Interlocked.CompareAndSwap
    • 分配给机器字长变量,如 int
  • 消息传递
    • MPI
    • 障碍
    • 等等

基本上,首先了解您的问题,然后选择工具/模式来解决它。

于 2012-07-24T02:53:05.563 回答
8

考虑对需要使线程安全的任何资源使用 lock 语句。

http://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}

这将是我的第一步。您也可以查看 Monitor 类。

http://msdn.microsoft.com/en-us/library/system.threading.monitor.aspx

这是在并发操作期间保护资源的两种基本方法。还有许多其他方式,例如互斥锁、信号量、条件读/写锁等。

于 2012-07-24T01:57:35.767 回答
1

从这里开始:为多线程同步数据

基本上,您需要使用mutex。在 .NET 中,每个对象都可以充当互斥锁,因此您可以在任何对象上使用lock 关键字来确保互斥。

于 2012-07-24T01:59:20.317 回答