Solved

Corss thread problem

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

Space-Age Communications Transitions to DevOps

ViaSat, a global provider of satellite and wireless communications, securely connects businesses, governments, and organizations to the Internet. Learn how ViaSat’s Network Solutions Engineer, drove the transition from a traditional network support to a DevOps-centric model.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Name Space error VS2015 1 36
Please explain purpose of GZIP 4 58
Consume a webservice via VB in Visual Studio 2015 3 19
VB.net Filesystem watcher not working 5 37
This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

749 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