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 不包含“产量”的定义

都铎王朝的回答。此方法仅适用于 .Net 4.0 及更高版本。

理想情况下,我希望一个线程启动并希望每个线程执行 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是一种 .NET 4.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 回答