【问题标题】:Thread inside a thread线程内线程
【发布时间】:2016-10-28 02:55:47
【问题描述】:

这个thread 将使用class 来处理某个事务。但要求是,这个class需要是一个线程,以避免两个线程同时访问这个class时速度变慢。我怎样才能制作一个thread

【问题讨论】:

标签: c# multithreading windows-services


【解决方案1】:

多线程应用程序之间的共享资源可以使用锁或 Monitor.Enter 逻辑进行同步。下面是一些基本多线程理解的参考链接

【讨论】:

    【解决方案2】:

    当多个线程同时访问一个对象时,不会固有减速,但如果数据读取和写入混合在一起,您可能会遇到竞争条件问题。一个典型的解决方案是使用lock statementsynchronize access to the object。请记住,多线程编程可能很难正确进行。

    【讨论】:

      【解决方案3】:

      我做了一个如何安全地从多个线程访问资源的例子。

      线程不安全版本

      class Program
      {
          private static decimal _balance = 100;
      
          static void Main(string[] args)
          {
              for (var i = 0; i < 10; i++)
              {
                  ThreadPool.QueueUserWorkItem(Withdraw, 23m);
              }
      
              Console.ReadLine();
          }
      
          private static void Withdraw(object state)
          {
              var value = (decimal)state;
              var prevBalance = _balance;
      
              if (_balance >= value)
              {
                   Thread.Sleep(50); // simulate longer operation to emphasize data corruption
                  _balance = _balance - value;
                  Console.WriteLine("Balance {0}. Withdraw {1}. Balance after withdraw {2}", prevBalance, value, _balance);
              }
      
              Console.WriteLine("Balance {0}. Withdraw failed", prevBalance);        
          }
      }    
      

      此代码将导致意外(和无法预测)的结果,因为变量_balance 是同时从多个线程访问和写入的。 _balance 可以为负数,即使我们在提款前检查余额。

      结果

      线程安全版本

      为了使线程以上的withdraw方法安全,你需要将方法体包裹在lock语句中。

      class Program
      {
          private static decimal _balance = 100;
          private static readonly object _balanceLocker = new object();
      
          static void Main(string[] args)
          {
              for (var i = 0; i < 10; i++)
              {
                  ThreadPool.QueueUserWorkItem(Withdraw, 23m);
              }
      
              Console.ReadLine();
          }
      
          private static void Withdraw(object state)
          {
              lock (_balanceLocker)
              {
                  var value = (decimal)state;
                  var prevBalance = _balance;
      
                  if (_balance >= value)
                  {
                      Thread.Sleep(50); // simulate longer operation to emphasize data corruption
                      _balance = _balance - value;
                      Console.WriteLine("Balance {0}. Withdraw {1}. Balance after withdraw {2}", prevBalance, value, _balance);
                      return;
                  }
      
                  Console.WriteLine("Balance {0}. Withdraw {1}. Withdraw failed", prevBalance, value);
              }
          }
      }    
      

      使用上面的代码,即使_withdraw 被多个线程访问,它也永远不会为零。

      结果

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-05
        • 2015-04-14
        • 1970-01-01
        • 2013-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-19
        相关资源
        最近更新 更多