1

.Netのスレッドの概念を理解しようとしています。Yield()メソッドを使用できません。10で割り切れるようになったときに、コントロールを並列スレッドに移動させたい。

助けてください。

以下は私のサンプルコードです:

class ThreadTest
{
    //Index i is declared as static so that both the threads have only one copy
    static int i;


    static void Main(string[] args)
    {
        Thread t = new Thread(WriteY);          
        i = 0;

        //Start thread Y    
        t.Start();                              
        //Do something on the main thread.
        for (; i < 100; i++)
        {
            if (i % 10 == 0)
            {
                //Simulate Yield() function
                Thread.Sleep(0);
                Console.WriteLine("The X thread");
            }
            Console.Write(i + ":X ");
        }
        Console.ReadKey(true);
    }

    static void WriteY()
    {
        for (; i < 100; i++)
        {
            if (i % 10 == 0)
            {
                //Simulate Yield() function
                Thread.Sleep(0);
                Console.WriteLine("The Y thread");
            }
            Console.Write(i + ":Y ");
        }
    }
}

コンパイル時エラーが発生します:

System.Threading.Threadには、「Yield」の定義が含まれていません

チューダーが答えた。この方法は、.Net4.0以降でのみ機能します。

理想的には、1つのスレッドを開始し、各スレッドを10ずつiずつ実行するようにします。現在の方法では、すべて「X」またはすべて「Y」を取得します。

編集: TudorとTheHeからの入力で-私は交互のXとYを取得することができました。問題の核心はロックオブジェクトの使用でした。ただし、このコードの出力は予測できません。

4

3 に答える 3

2

忘れるThread.Yield; それはあなたがやろうとしていることとは無関係です。最終的には、アクセスを同期するためlockに使用するがあります。Monitorの内部ではlock、スレッドが排他的にアクセスできます。あなたがする必要があるのは一時的にロックを放棄することです。あなたがそれをする方法はMonitor.Wait。ただし、の場合はWait、「準備完了」キューではなく「待機中」キューに入ることになります。したがって、各スレッドが確実に注目されるようにするにPulseは、の前と最後の両方で、を行う必要がありますWait(両方のスレッドが終了する機会を確実に得るため)。どうぞ:

using System.Threading;
using System;
class ThreadTest
{
    //Index i is declared as static so that both the threads have only one copy
    static int i;

    //The lock object
    static readonly object locker = new object();

    static void Main(string[] args)
    {
        Thread t = new Thread(WriteY);

        i = 0;

        //Start thread Y
        t.Start();
        lock (locker)
        {
            // Print X on the main thread
            for (; i < 100; i++)
            {
                if (i % 10 == 0)
                {
                    Monitor.PulseAll(locker); // move any "waiting" threads to the "ready" queue
                    Monitor.Wait(locker); // relinquish the lock, and wait for a pulse
                    Console.WriteLine("The X thread");
                }
                Console.Write(i + ":X ");
            }
            Monitor.PulseAll(locker);
        }
        Console.ReadKey(true);
    }

    static void WriteY()
    {
        lock (locker)
        {
            for (; i < 100; i++)
            {
                if (i % 10 == 0)
                {
                    Monitor.PulseAll(locker); // move any "waiting" threads to the "ready" queue
                    Monitor.Wait(locker); // relinquish the lock, and wait for a pulse
                    Console.WriteLine("The Y thread");
                }
                Console.Write(i + ":Y ");
            }
            Monitor.PulseAll(locker); // move any "waiting" threads to the "ready" queue
        }
    }
}
于 2012-09-14T09:23:24.380 に答える
2

Thread.Yieldスケジューラーが実行の準備ができている別のスレッドを選択できるようにするだけです。

呼び出し元のスレッドに、現在のプロセッサで実行する準備ができている別のスレッドに実行を譲らせます。オペレーティングシステムは、譲歩するスレッドを選択します。

アプリケーション内の他のスレッドもそのロックを待機している場合は、必要なものをすべて生成できますが、実行する機会はありません。

ところで、Yield.NET4.0以降のメソッドです。以前のバージョンをターゲットにしていないことを確認してください。

編集:IMO、あなたが望むことをするためにあなたはイベントを使うべきです:

class Test
{
    //Index i is declared as static so that both the threads have only one copy
    static int i;

    static AutoResetEvent parentEvent = new AutoResetEvent(true);
    static AutoResetEvent childEvent = new AutoResetEvent(false);

    static void Main(string[] args)
    {
        Thread t = new Thread(WriteY);

        i = 0;

        //Start thread Y
        t.Start();
        // Print X on the main thread
        parentEvent.WaitOne();
        while (i < 100)
        {                
            if (i % 10 == 0)
            {
                childEvent.Set();
                parentEvent.WaitOne();
            }
            Console.Write(i + ":Y ");
            i++;
        }
        t.Join();
    }

    static void WriteY()
    {
        childEvent.WaitOne();
        while (i < 100)
        {
            if (i % 10 == 0)
            {
                parentEvent.Set();
                childEvent.WaitOne();
            }
            Console.Write(i + ":X ");
            i++;
        }
    }
}
于 2012-09-14T08:27:11.653 に答える
1

私の観点からすると、あなたは現在のスレッドで「ロッカー」をロックしていて、現在のタスクを他のスレッドに譲りたいと思っています...ロックは常に最初のスレッドによって保持されています-それは機能しませんか?!

複数のスレッドを使用する場合は、オブジェクトを手動でロックする必要があります。

于 2012-09-14T08:18:22.003 に答える