c# - 任务并行库 (TPL) 中的线程同步

标签 c# multithreading task-parallel-library

我正在学习 TPL 并且有疑问。仅供学习之用,希望大家指导我正确的方向。

我希望一次只有一个线程访问变量 sum,这样它就不会被覆盖。

我的代码如下。

using System;
using System.Threading.Tasks;


class ThreadTest
{
    private Object thisLock = new Object();
    static int sum = 0;
    public void RunMe()
    {
        lock (thisLock)
        {
            sum = sum + 1;
        }
    }

    static void Main()
    {
        ThreadTest b = new ThreadTest();
        Task t1 = new Task(()=>b.RunMe());
        Task t2= new Task(() => b.RunMe());
        t1.Start();
        t2.Start();
        Task.WaitAll(t1, t2);
        Console.WriteLine(sum.ToString());
        Console.ReadLine();
    }
}

问题 - 我在这段代码中是否正确?

问题-我可以不带锁地做吗,因为我在某处读到它应该避免,因为它不允许任务相互通信。我已经看到一些异步和等待的例子但是我正在使用 .Net 4.0。

谢谢

最佳答案

Am i right in this code

在实现方面是的,但在理解方面是不可行的,因为您在尝试实现逻辑时混淆了新旧世界,让我尝试详细解释一下。

  • Task t1 = new Task(()=>b.RunMe()); 并不像 Thread API 中的预期那样意味着每个新线程时间
  • Task API 将调用一个线程池线程,因此有可能是两个 Task 对象 t1,t2,大多数时候在同一个线程上执行一个短时间运行的逻辑并且在尝试更新共享对象
  • 时,永远不会出现需要显式锁定的竞争条件
  • 防止 Sum object 竞争条件的更好方法是 Interlocked.Increment(ref sum),这是一种对 执行基本操作的线程安全机制原始类型
  • 对于您正在执行的操作,更好的 API 是 Parallel.For,而不是创建单独的 Task,好处是您可以以最小的努力运行任意数量的此类 increment 操作,而不是创建一个单独的任务,它会自动阻塞主线程,因此您的代码应如下所示:

    using System;
    using System.Threading.Tasks;
    
    class ThreadTest
    {    
       public static int sum;
    }
    
    static void Main()
    {
    
     Parallel.For(0, 1, i =>
    {
        // Some thread instrumentation
        Console.WriteLine("i = {0}, thread = {1}", i,
        Thread.CurrentThread.ManagedThreadId);
    
        Interlocked.Increment(ref ThreadTest.sum);
    });
    
       Console.WriteLine(ThreadTest.sum.ToString());
       Console.ReadLine();
    }
    }
    
  • 在使用 Thread 检测时,您会发现对于两个循环,0,1managed thread id 可能是相同的,从而避免了需要如前所述,为了线程安全

关于c# - 任务并行库 (TPL) 中的线程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39139151/

相关文章:

c# - 如何使用 msTSProfilePath、msTSHomeDirectory 等扩展 C# DirectoryServices UserContext

C# - ListBox DataSource 属性和绑定(bind) ArrayList

c++ - 我的多线程程序在双核机器上运行缓慢或出现死锁,请帮忙

java - 有没有办法确定理想的线程数?

c# - 并行 foreach 字符数组空白

c# - 在 Task.Run 中使用 CancellationToken 超时不起作用

c# - 如何在 ASP.NET MVC 中使用 NLog 记录客户端 IP 地址

java - 我无法在 Unity3D 中构建 Android 应用程序。错误 Gradle 初始化失败

c# - 适用于数百个消费者和大文件的好方法

c# - 具有基于任务的异步模式的 UDP 监听器