如何在c#上使对象线程安全?

时间:2012-07-24 01:53:39

标签: c# .net thread-safety

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

您是否有任何建议如何使对象成为线程安全的并确保每个线程的对象都正确?我应该制作变量static吗?

3 个答案:

答案 0 :(得分:16)

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

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

enter image description here

一旦你有了事先发生的图表,很容易看出在其他事情发生之前会发生什么,但更重要的是它会向你显示在其他事情发生之前不会发生的事情。

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

C#.net 4.0具有许多用于并行编程的有用功能。

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

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

实用模式:

  • 任务
  • 平行循环
  • 生产者/消费者
  • 管道
  • 工作列表
  • MapReduce的

有用的工具:

  • 任务并行库
    • Parallel.For
    • Parallel.Foreach,
    • 任务
  • PLINQ
  • 并发DataStructures
    • ConcurrentQueue
  • 锁定
    • 'lock'关键字
    • 监控(与'锁'相同的功能)
    • 信号灯
    • 自旋锁
    • 读/写锁
  • 硬件原子操作
    • Interlocked.Increment
    • Interlocked.Add
    • Interlocked.CompareAndSwap
    • 分配机器字长变量,如int
  • 消息传递
    • MPI
    • 障碍

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

答案 1 :(得分:5)

使用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

这些是您可以在并发操作期间保护资源的两种基本方法。还有许多其他方法,如互斥,sempahores,条件读/写锁等。

答案 2 :(得分:1)

从这里开始:Synchronizing Data for Multithreading

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