【问题标题】:Locking is not working锁定不起作用
【发布时间】:2013-08-07 23:15:26
【问题描述】:

这是我的代码:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication4
{
    class Writer {
        public void Write(string xxx) { Console.Write(xxx); }

    }
    class Program
    {
        static Writer wrt;

        static void Main(string[] args)
        {
            wrt = new Writer();
            Thread trd = new Thread(new ThreadStart(delegate() {
                lock (wrt)
                {
                    Thread.Sleep(1000);
                    wrt.Write("1");
                }
            }));
            trd.Start();
            wrt.Write("0");
            Console.ReadLine();
        }
    }
}

例外的输出是“10”,但输出是“01”。为什么?

【问题讨论】:

  • 我希望它显示 01
  • lock 将使用对象作为“隔离机制”来“隔离”代码块。您没有锁定对象..您正在隔离代码块。

标签: c# multithreading monitor thread-synchronization


【解决方案1】:

两个地方都需要锁定:

        wrt = new Writer();
        Thread trd = new Thread(new ThreadStart(delegate() {
            lock (wrt)
            {
                Thread.Sleep(1000);
                wrt.Write("1");
            }
        }));
        trd.Start();

        lock(wrt) // Lock here, too
        {
            wrt.Write("0");
        }
        Console.ReadLine();

使用lock 不会阻止该实例在其他地方使用,它只是阻止该实例被用于获取另一个锁,直到您的lock 完成。

不要将lock 视为“锁定对象”,而是将其视为您的对象是该锁的唯一且唯一的钥匙 - 没有其他lock(yourObject) 可以“解锁”该代码块,直到第一个代码块完成了。

请注意,这仍然可能会显示“01”作为输出,因为线程不太可能以足够快的速度启动以首先获得lock,但这不是确定性的。

【讨论】:

    【解决方案2】:

    为什么不使用任务?它将确保第一个线程在继续下一个线程之前完成。

     class Program
    {
        static void Main(string[] args)
        {
            var writer = new Writer();
    
            var task = Task.Factory.StartNew(() =>
                {
                    writer.Write("1");
                });
    
            task.ContinueWith((data) =>
            {
                writer.Write("0");
            });
    
            Console.ReadKey();
        }
    }
    
    public class Writer
    {
        public void Write(string message)
        {
            Console.Write(message);
        }
    }
    

    【讨论】:

      【解决方案3】:

      主线程中的wrt.Write("0");语句在trd线程之前执行。主线程启动trd 线程并继续执行主线程下的语句,这就是为什么主线程下的Write 语句在trd 线程之前执行。

      lock 语句在 trd 线程内部,因此与主线程下的 wrt.Write 无关。您可以按照Reed Copsey 的建议将锁锁定在主线程上,但您无法确保哪个线程将首先获得锁定。它可能是首先获得锁的主线程。

      您可以通过在启动线程 trd 后调用 Thread.Join 来确保 trd 线程在主线程之前完成执行,这将确保主线程将等待直到 trd 线程完成执行。这将确保您得到 10 而不是 01。

      static Writer wrt;  
      
      static void Main(string[] args)
      {
          wrt = new Writer();
          Thread trd = new Thread(new ThreadStart(delegate() {
              lock (wrt)
              {
                  Thread.Sleep(1000);
                  wrt.Write("1");
              }
          }));
          trd.Start();
          trd.Join();
          wrt.Write("0");
          Console.ReadLine();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-06
        • 1970-01-01
        • 2017-01-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多