Patryk
Patryk

Reputation: 3152

Creating objects in a main thread and working with them in another thread. How to do that?

Right Now, it outputs 00, instead of 54. I'm learning with threads and I stuck here, I don't know what to do now

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        Point[] array = new Point[20];
        public Form1()
        {
            for (int i = 0; i < 20; i++)
            {
                array[i] = new Point(); // I'm creating objects here
            }
            InitializeComponent();
        }

        void function1()
        {
            array[0].x = 5;
            array[0].y = 4;
        }

        void function2()
        {
            label1.Text = array[0].ToString();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Thread thread1 = new Thread(function1);
            thread1.Start();
            Thread.Sleep(500);
            function2();
        }
    }

    class Point
    {
        public int x;
        public int y;
        public override string ToString()
        {
            return x.ToString() + y.ToString();
        }
    }  
}

when Im doing it in that way (without another thread)

private void Form1_Load(object sender, EventArgs e)
{
    function1();
    function2();
}

It works fine, output is 54 thanks

Upvotes: 1

Views: 2054

Answers (4)

Brian Gideon
Brian Gideon

Reputation: 48949

If function2 is dependent upon the completion of function1 then you need to make sure function1 really does complete before function2 starts. Using Thread.Sleep for that job will not always work because of the unpredictable nature of how threads are scheduled and executed.

Another problem with Thread.Sleep is that it is blocking the UI thread. The number one rule when using multithreading in UI based application is to never block the UI thread. This applies to any kind of blocking call including Thread.Sleep, ManualResetEvent, Thread.Join, etc.

The way I would approach this problem is to use the Task class with the ContinueWith method. This will wait for function1 to complete before calling function2 without blocking the UI thread.

private void Form1_Load(object sender, EventArgs e)
{
  TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

  Task.Factory.StartNew(() =>
  {
    function1();
  }).ContinueWith((task =>
  {
    function2();
  }, ui);
}

Upvotes: 1

Ňuf
Ňuf

Reputation: 6207

Actually your program is working on my computer as expected. So why it's not working on your computer (or is working only sometimes)? This is because there is race condition in your program. This means that your program assumes that the second thread (that executes function1) will assign new values to array in less than 500ms. Never make any ASSUMPTION about how long it takes for the other thread to complete it's task. Operating system is free to choose when, how often and how long individual threads executes and when it suspends them. Instead, use synchronization primitives (such as ManualResetEvent) to MAKE SURE that the second thread has done it's task.

This code shows, how you can change your program do thread synchronization properly:

    ManualResetEvent MRE = new ManualResetEvent(false);//Add this field to Form1

    void function1()
    {
        array[0].x = 5;
        array[0].y = 4;
        MRE.Set();//This notifies first thread, that values are set.
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Thread thread1 = new Thread(function1);
        thread1.Start();
        MRE.WaitOne();//This makes this thread wait until the second thread calls MRE.Set()
        function2();
    }

Upvotes: 2

Martin James
Martin James

Reputation: 24857

You code, as supplied, will not compile because of the missing ';' afer the Sleep(500) call.

Whwn the syntax is fixed, it 'works' on my box.

You have no secure way of signalling that it has finished. You are learning so, first lesson - don't wait for threads with sleep() calls.

A BackgroundWorker component would be easier to use - you don't have to worry about explicit signalling to get a result back.

If you want to stick with the Thread instance, look at autoResetEvent class or Thread.Join().

enter image description here

Upvotes: 0

Tudor
Tudor

Reputation: 62439

What you are doing does not make much sense. You are starting a thread, then sleeping for 500ms and then calling the function that uses the results of that thread.

This means that your two actions are sequentially dependent and cannot execute in parallel. Using threads here is meaningless.

And the reason you are not seeing the changes is probably because thread1 does not have enough time to start and execute its code before the sleep finishes and function2 is called. Try to use thread1.Join() instead, but like I said, this makes no sense at all!

Upvotes: 2

Related Questions