Solved

Corss thread problem

Posted on 2009-05-18
3
323 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:
Munawar Hussain 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:Munawar Hussain
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

Visualize your virtual and backup environments

Create well-organized and polished visualizations of your virtual and backup environments when planning VMware vSphere, Microsoft Hyper-V or Veeam deployments. It helps you to gain better visibility and valuable business insights.

Question has a verified solution.

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

For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
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…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…

635 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