【问题标题】:Lock() in multithreading program多线程程序中的 Lock()
【发布时间】:2016-07-25 14:47:45
【问题描述】:

我有一个简单的程序来模拟我的错误情况。我有一个从多个线程获取消息的单例类。必须阻塞执行,直到函数执行完毕。

class Program
{
    private static TestClass test;
    static void Main(string[] args)
    {
        Thread a = new Thread(TestFunctionB);
        a.Start();

        Thread b = new Thread(TestFunctionB);
        b.Start();
    }

    private static void TestFunctionB()
    {
        TestClass test = TestClass.Instance;
        for (int i = 0; i < 15; i++)
        {
            test.Handle(i, Thread.CurrentThread.ManagedThreadId);
        }
    }
}

class TestClass
{
    private readonly object _lockObject;
    private static TestClass _instance;

    private TestClass()
    {
        _lockObject = new object();
    }

    public static TestClass Instance
    {
        get { return _instance ?? (_instance = new TestClass()); }
    }

    private void RunLocked(Action action)
    {
        lock (_lockObject)
        {
            action.Invoke();
        }
    }

    public void Handle(int counter, int threadId)
    {
        Console.WriteLine("\nThreadId = {0}, counter = {1}\n", threadId, counter);

        RunLocked(() =>
                  {
                      Console.WriteLine("\nFunction Handle ThreadId = {0}, counter = {1}\n", threadId, counter);

                      for (int i = 0; i < 30; i++)
                      {
                          Console.WriteLine("Funktion Handle threadId = {0}, counter = {1}, i = {2}", threadId, counter, i);
                          //Thread.Sleep(100);
                      }

                  });

        Console.WriteLine("\nFunction Handle free ThreadId = {0}, counter = {1}\n", threadId, counter);

    }


}

`

我希望线程一个接一个地写入输出,但在控制台中线程输出是混合的。 lock 语句不正确吗?

【问题讨论】:

  • 您预计会发生什么? lock 确保在委托期间没有其他线程将获得它(但不保证它之前或之后的任何东西)。所以第一个线程将完成完整的循环(30 次迭代),然后是第二个。你想要什么?打印单个消息?一个来自一个线程,一个来自另一个线程?
  • 我也希望如此。但是在控制台窗口中我有 f.e.来自线程 1 的 20 个字符串,然后来自线程 2 的 12 个字符串。
  • 原因可能确实是单例实现不佳,请参阅@Scott 答案。最初我虽然你得到了这种行为,但你期望一些不同的东西。
  • 字段private static TestClass test;有什么作用?
  • Nothing:) 来自另一个实现

标签: c# multithreading locking


【解决方案1】:

我不知道这是否是您唯一的问题,但 get { return _instance ?? (_instance = new TestClass()); } 不是原子的,您最终可能会返回多个实例。

使用Lazy&lt;T&gt; 类保证只创建一个单例实例。

class TestClass
{
    private readonly object _lockObject;
    private readonly static Lazy<TestClass> _instance = new Lazy<TestClass>(x=> new TestClass());

    private TestClass()
    {
        _lockObject = new object();
    }

    public static TestClass Instance
    {
        get { return _instance.Value; }
    }
    ...
}

如果您无法访问 .NET 4.0 或更高版本,则需要锁定您的单例创建。

class TestClass
{
    private readonly object _lockObject;
    private static readonly object _singletonLock = new Object();
    private static TestClass _instance;

    private TestClass()
    {
        _lockObject = new object();
    }

    public static TestClass Instance
    {
        get 
        { 
            if(_instance == null)
            {
                lock(_singletonLock)
                {
                    if(_instance == null)
                    {
                        _instance = new TestClass ();
                    }
                }
            }
            return _instance; 
        }
    }
    ...
}

【讨论】:

    猜你喜欢
    • 2021-05-26
    • 1970-01-01
    • 1970-01-01
    • 2016-07-19
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 2010-11-17
    • 2017-01-11
    相关资源
    最近更新 更多