TheSilverBullet
TheSilverBullet

Reputation: 625

Thread Yield method simulation using Sleep

I am trying to understand threading concepts in .Net. I am unable to use Yield() method. I want the control to go to a parallel thread when i becomes divisible by 10.

Please help.

Below is my sample code:

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 ");
        }
    }
}

I get the compile time error:

System.Threading.Thread does not contain a definition for 'Yield'

Answered by Tudor. This method will only work on .Net 4.0 and upwards.

Ideally I would want one thread to start and want each thread to execute for 10 incremented of i each. With my current method, I either get all 'X' or all 'Y'.

Edit: With inputs from Tudor and TheHe - I have been able to get alternate X and Y. The crux of the problem was usage of lock object. But the output of this code is not predictable.

Upvotes: 1

Views: 2466

Answers (3)

Marc Gravell
Marc Gravell

Reputation: 1063569

Forget Thread.Yield; that is unrelated to what you are trying to do. Ultimately, you have a lock, which uses Monitor to synchronize access. Inside the lock, your thread exclusively has access. What you need to do is relinquish the lock temporarily; the way you do that is with Monitor.Wait. However, if you Wait, you also end up in the "waiting" queue rather than the "ready" queue, so in order to make sure that each thread gets attention, we also need to Pulse, both before the Wait, and also at the end (to make sure both threads get chance to exit). Here we go:

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
        }
    }
}

Upvotes: 2

Tudor
Tudor

Reputation: 62459

Thread.Yield will simply enable the scheduler to select a different thread that is ready to run:

Causes the calling thread to yield execution to another thread that is ready to run on the current processor. The operating system selects the thread to yield to.

If other threads in your application are also waiting on that lock, you can yield all you want, they won't get a chance to run.

Btw, Yield is a .NET 4.0+ method. Make sure you're not targeting an earlier version.

Edit: IMO, to do what you want you should use events:

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++;
        }
    }
}

Upvotes: 2

TheHe
TheHe

Reputation: 2972

from my point of view, you're locking "locker" in current thread and want to yield the current task to an other thread... the lock is held by the first thread all the time -- it can't work?!

you have to manually lock the objects if you want to use multiple threads...

Upvotes: 1

Related Questions