2

这是我的代码:

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”。为什么?

4

3 回答 3

8

您需要锁定两个地方:

        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();

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

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

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

于 2013-08-07T23:17:33.537 回答
1

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

 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);
    }
}
于 2013-08-07T23:48:26.703 回答
0

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

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

您可以通过在启动线程 trd 后调用Thread.Jointrd来确保线程在主线程之前完成执行,这将确保主线程将等待直到 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();
}
于 2013-08-07T23:18:48.713 回答