Solved

Corss thread problem

Posted on 2009-05-18
3
321 Views
Last Modified: 2013-12-17
I am having a hard time understanding Cross thread operation.  I have a few questions from the code below.

1.  In DoStuff() method, I have 'this.Invoke((MethodInvoker) delegate { this.button1.Enabled = true; });'.  if I remove this line of code and add 'this.button1.Enabled = true;' at the end of private void button1_Click(object sender, EventArgs e), the button1 is enabled while the DoStuff() is still running.  Is that because DoStuff() is running on a thread, 't' and this.button1.Enabled = true is running on the main thread?  

2. I want the button1 is enabled after all the tasks in DoStuff() is ended.  Is that the reason that I had to put enabling button1 code at the end of DoStuff() method?

3.  The enabling button1 code in DoStuff() method should be written as 'this.Invoke((MethodInvoker) delegate { this.button1.Enabled = true; });'  If I write 'this.button1.Enabled = true ', I am getting an error.  Is that because a whole method DoStuff() is running on a separated thread(not a main thread) and enabling button1 code is part of DoStuff() method?

4. Could you please explain the syntax of ''this.Invoke((MethodInvoker) delegate { this.button1.Enabled = true; });''  I understand that it's using an anonymous method.  Could you lease explain the use of Invoke and MethodInvoker here?  (What are  'Invoke' and 'MethodInvoker' and why do I need to use them here and what are they doing here etc.)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
 
namespace RichTextDelay
{
    public partial class Form1 : Form
    {
        Thread backgroundThread = null;
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            this.button1.Enabled = false;
            this.richTextBox1.Update();
            this.richTextBox1.Clear();
            backgroundThread = new Thread(delegate() { DoStuff(); });
            backgroundThread.Start();
        }
        private void DoStuff()
        {
            for (int i = 0; i < 3; i++)
            {
                AddHi(i);
                Thread.Sleep(10000);
                AddBye(i);
            }
            this.Invoke((MethodInvoker) delegate { this.button1.Enabled = true; });
        }
       
        public delegate void GreetingDelegate(string str);
        public void AddGreeting(string str)
        {
            if (this.richTextBox1.InvokeRequired)
            {
                this.richTextBox1.Invoke(new GreetingDelegate(AddGreeting), str);
                return;
            }
            else
            {
                this.richTextBox1.AppendText(str);
                this.richTextBox1.Refresh();
            }
        }        
        public void AddHi(int i)
        {
            try
            {
                AddGreeting("Hi " + i.ToString() + "\n");
 
            }
            catch (Exception e)
            {
                e.Message.ToString();
            }
        }
 
        public void AddBye(int i)
        {
            try
            {
                AddGreeting("Bye " + i.ToString() + "\n");
 
            }
            catch (Exception e)
            {
                e.Message.ToString();
            }
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (backgroundThread != null)
            {
                backgroundThread.Abort();
                backgroundThread = null;
            }
        }        
    }
}
0
Comment
Question by:IzzyTwinkly
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 12

Accepted Solution

by:
needo_jee earned 500 total points
ID: 24418345
hi,

1- button click routine calls method of other thread, leaves it working separately and moves ahead to process instruction available at current thread. Thats why it enables the button but other thread/method still keep running. It would not wait for completion of DoStuff() because its at another thread

2- it is obvious that you need to enable your button from DoStuff() , using a delegate via invoke because your main thread does not know when DoStuff()  is going to finish its work. There is possibility to enable it from main thread but that would be an overhead of adding a shared class member and keep monitoring continuously. DoStuff() will update the shared member that work is completed and the main thread that is monitoring the shared member will enable the button. But I suggest using a delegate and enable it from  DoStuff () at the end.

3- yes , put your enabling code in DoStuff., at the end.

4- you need to use invoke, this is a way to let threads talk to each other. when you call invoke, first it checks whether any other thread is accessing it or not, is it locked or not, then it takes hold of that resource as if it was created on current thread and releases after performing the operation. Invoke calls same methods via other thread while directly calling a method is on current/main thread

Like, you have this line inside a method, when pointer reaches this line, it calls method again from current thread (in your case backgroundworker)

you have this line this.richTextBox1.Invoke  in AddGreeting method, when you call AddGreeting and it reaches the line richTextBox1.Invoke, it checks the owner of this control if current thread is not then it would call AddGreeting method again via invoke to take the control.

5- could not understand question exactly, invoker method means , method that you want to use as invoker / caller

in your case, your are calling AddGreeting via GreetingDelegate


-thanks

0
 

Author Comment

by:IzzyTwinkly
ID: 24419242
Thanks needo, but I still don't understand '''this.Invoke((MethodInvoker) delegate { this.button1.Enabled = true; });' syntax.  Why does it need to be casted to MethodInvoker?   what eactly happens when this line of code is executed?  According to you, it check if any other thread is using button1, then if none is using button1, it takes hold of resources for the action(this.button1.Enabled = true), correct?  Then what?  What has been converted to MethodInvoker?  Why do I need to do this here?
0
 
LVL 12

Expert Comment

by:needo_jee
ID: 24425911
hi,

here goes the explanation for your question.
For each control that we create an ID of thread is associated that its created on.

when we call InvokeRequired, it compares ID of current thread with ID of control associated thread ID, if they are different then it would return true and would need to work on this control via Invoke

Now what does invoke, i take this line from your code

this.richTextBox1.Invoke(new GreetingDelegate(AddGreeting), str);

Textbox is calling a delegate method asynchronously, we need an asynchronous call to make it thread safe, the other thread may be working on same resource (control), so this thread can wait until other is working.

to call asynch we use a parameterized delegate here  GreetingDelegate(AddGreeting) and in Invoke we pass delegate and parameter


lets say we dont use that way .. just simplly call AddGreeting(string str) directly without any invoke

there is no issue, in calling however, it would not be able to access any control associated with thread other than it was being created.

so, you need to make an asynch call , to do so you need to use deletegate. the parameter is your requirements however, its not a must to do.


just for a reference here is a link to know about thread safe and unsafe calls.
http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx


-thanks





0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below. https://filedb.experts-exchange.com/incoming/2017/03_w12/1151775/Permutations.txt https://filedb.experts-exchange.com/incoming/201…

738 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question