Solved

Corss thread problem

Posted on 2009-05-18
3
316 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
  • 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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Welcome my friends to the second instalment and follow-up to our Minify and Concatenate Your Scripts and Stylesheets (http://www.experts-exchange.com/Programming/Languages/.NET/ASP.NET/A_4334-Minify-and-Concatenate-Your-Scripts-and-Stylesheets.html)…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

708 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now