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

を使用しても、そのインスタンスが他の場所で使用されるlockのを防ぐことはできません。完了するまで、そのインスタンスが別のロックを取得するために使用されるのを防ぐだけです。 lock

「オブジェクトをロックする」と考えるlockのではなく、オブジェクトがそのロックの唯一の鍵であると考えてくださいlock(yourObject)。最初のコードブロックが完了するまで、他の誰もそのコードブロックを「ロック解除」できません。

lockスレッドが最初のものを取得するのに十分な速さで起動する可能性は非常に低いため、出力として「01」が表示される可能性が高いことに注意してください。ただし、それは決定論的ではありません。

于 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 スレッドが実行を終了するまで待機するようになります。これにより、01 ではなく 10 が得られます。

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 に答える