bk13

I found some example code in a web page titled ˇ°How to create a thread by using Visual C#ˇ± and located here:

http://support.microsoft.com/default.aspx scid=kb%3Ben-us%3B815804

The instructions in this tutorial are easy to follow and I think I followed them correctly. It took maybe 3 minutes. When I try to run the new project, it pops up the form, then a few seconds later a window titled ˇ°InvalidOperatorException was unhandled.ˇ± The Window has an option to ˇ°Copy exception detail to the clipboardˇ± so I did that and pasted the data in below.

The line of code highlighted is:


this.progressBar1.Value = newval;

I did it twice and obtained exactly the same results. Did I make an error Has anyone run this with the expected results

System.InvalidOperationException was unhandled

Message="Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on."

Source="System.Windows.Forms"

StackTrace:

at System.Windows.Forms.Control.get_Handle()

at System.Windows.Forms.Control.SendMessage(Int32 msg, Int32 wparam, Int32 lparam)

at System.Windows.Forms.ProgressBar.set_Value(Int32 value)

at ThreadWinApp.Form1.ThreadTask() in F:\A\Bryan\C_PROJECTS\ThreadwinApp\ThreadWinApp\ThreadWinApp\Form1.cs:line 42

at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

at System.Threading.ThreadHelper.ThreadStart()




Re: Visual C# General Sample code problem: creating threads

frederikm

Hi

you are accessing your form from the background thread, which is not allowed.

do the following:

-create a delegate

public delegate void UpdateDel();

- create a new method

private void UpdateBar() {

if (InvokeRequired) {

UpdateDel d = new UpdateDel(UpdateBar)

Invoke(d);

return;

}

this.progressBar1.Value = newval;

}

- change ThreadTask

private void ThreadTask()
{
int stp;
int newval;
Random rnd=new Random();

while(true)
{
stp=this.progressBar1.Step*rnd.Next(-1,2);
newval = this.progressBar1.Value + stp;

if (newval > this.progressBar1.Maximum)
newval = this.progressBar1.Maximum;
else if (newval < this.progressBar1.Minimum)
newval = this.progressBar1.Minimum;
  
UpdateBar();

  Thread.Sleep(100);
}
}

Hope this helps






Re: Visual C# General Sample code problem: creating threads

Lowendahl

The Invoke method in this case will post the delegate execution to the main thread message loop.

I got a more detailed and more explained example in this article here: Events in an asynchronous component model






Re: Visual C# General Sample code problem: creating threads

bk13

Hello Fredrik,

Thanks for taking the time that you have to think about my problem and post a reply. 

LATE EDIT:  Allow me to refresh my immediate goal.  I want to spawn off a thread that will receive UDP broadcast messages and pass six integers back to a function that will update those six values in a displayed window.  Once the data gets there, I can work with it. All of this is to understand how I can do that. End of late edit.

I made your changes as I understand them but am having a problem.  First, the compiler complains "The name 'newval' does not exist in the current context"  When the message is clicked it takes me to:

this.progressBar1.Value = newval;

This is within the procedure UpdateBar.  Indeed, the variable is not declared there.  I tried to add it as a parameter so the call would be UpdateBar( int newval ).  I think that is a viable alterternative, but I made an error somewhere and that change was not accepted.  I will try it again with some changes after I post.

I am not understaning how the delegate function operates.  I put some comments in the code and am hoping that you (or someone) will clarify.  

Lowendahl,

Thanks for the link.  It is still a bit over my head but I will study it. What do you mean by marshalling


using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Threading;

namespace ThreadWinApp
{
public partial class Form1 : Form

{
private Thread trd;
 
// Create a name (alias ) that can be used to call a function but

// can be passed as a parameter.

public delegate void UpdateDel();
 
// this procedure will update the progress bar in the window.

private void UpdateBar()
{
// If this procedure was called from a thread that is not where

// the procedure was declared/created (right wording ), then

// InvokeRequired will be true meaning that this procedure cannot

// be directly called. It must be called via a delegate.

if (InvokeRequired)
{
// This procedure appears to be assigning itself as the delegate.

// I suspect that the Invoke(d) essentially causes the UpdateBar

// to be called from the original thread. In that event, the

// if statement will not be taken, and the progress bar will be

// udated.

// I don't understand what is going on here.

UpdateDel d = new UpdateDel(UpdateBar);
Invoke(d);
return;
}
// This is the statement we want to be executed to update the

// progress bar.

this.progressBar1.Value = newval;
}
public Form1()
{
InitializeComponent();
}
 
// Give the button something to show it is an active component.

private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("This is the main thread");
}
 
// this is the task to be spawned off. When the form is loaded

// function Form1_Load is called and it starts this function as

// a separated task. It will calculate a new value for the

// progress bar, update the prgress bar, then sleep for 0.2 seconds

// BUT: UpdateBar will not be running within the same thread as

// this function. That is handled elsewhere.

private void ThreadTask()
{
int stp;
int newval;
Random rnd = new Random();
while (true)
{
stp =
this.progressBar1.Step * rnd.Next(-1, 2);
newval =
this.progressBar1.Value + stp;
if (newval > this.progressBar1.Maximum)
newval =
this.progressBar1.Maximum;
else if (newval < this.progressBar1.Minimum)
newval =
this.progressBar1.Minimum;
UpdateBar( );
// I think newval should be passed as a parameter here.

//this.progressBar1.Value = newval;  // orignal code removed

Thread.Sleep(100);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Thread trd = new Thread(new ThreadStart(this.ThreadTask));
trd.IsBackground =
true;
trd.Start();
}
 
 
 
}
}


 






Re: Visual C# General Sample code problem: creating threads

bk13

Hello Patrik,

I need some help understanding your paper ˇ°Events In An Asynchronous Component Modelˇ± This may work out better if state my underlying goals.

Focus & Urgency

I have a patent application in progress and I need to develop a prototype to demonstrate it.

Basic Concept

Display a window with six integers for raw. Spawn off a process that collects the six integers from an embedded computer via Ethernet (wireless eventually). The embedded computer is very simple: it makes measurements and throws out the data via UDP (think simple) maybe ten times per second. When the integers are updated, process the data and display the results in a few more windows. I have written a console program that receives the data from the embedded computer. It works, but it cannot display the results in a meaningful manner as I think I can in a windows environment.

I looked up messaging and queuing and did not see anything that I could use to pass data between threads. For various reasons I conclude I must spawn off a thread and somehow use a delegate to get the information from the UDP manager back to the main process. That is how I got here.

From your web page (white paper ):

When a delegate object invokes its target function, it will be executed by the current thread requesting the invocation.

I will word this in the concept I laid out above. Where does this delegate object reside, the main thread or the spawned UDP processing thread I am guessing that the delegate is an object in the spawned thread that represents the function in the main thread. Somehow, this allows the spawned thread to call a function in the main thread passing arguments. Hopefully, that delegate (right word here ) can accept an array of bytes or six integers such that back in the main thread, the six integers will be available to put somewhere.

Back to this thread. If I can get the progress bar program working, I think I can replace the random number generator with the code to get UDP messages and pass the numbers from those messages back to the main task.

Am I in the right ball part Have I explained this clearly Can you advise me






Re: Visual C# General Sample code problem: creating threads

Evan Mulawski

Under InitializeComponent() in the public Form1 section, put this:

CheckForIllegalCrossThreadCalls = false;

This prevents exceptions when performing cross-thread functions.






Re: Visual C# General Sample code problem: creating threads

bk13

Hello Evan,

As I continue to understand this, I just came across this help page about exactly that:

ms-help://MS.VSExpressCC.v80/MS.NETFramework.v20.en/dv_fxmclictl/html/138f38b6-1099-4fd5-910c-390b41cbad35.htm

On that page I find:

This exception occurs reliably during debugging and, under some circumstances, at run time. You are strongly advised to fix this problem when you see it. You might see this exception when you debug applications that you wrote with the .NET Framework prior to .NET Framework version 2.0.

It seems to me that the help file advises against this. I have not yet extracted the meat out of the example file on this page, but I suspect I may not want to do that. Can you understand what the HUGE example code is telling us to do so this can run in a safe manner






Re: Visual C# General Sample code problem: creating threads

Evan Mulawski

Cross threads are basically this:

When a function tries to edit, (say the text of), a control, and another function needs to change the text of that same control again, because they are on the same thread and both attempting to do the same thing, an exception occurs warning you of a possible "Mis-hap", if you will.

The InvalidOperationException can be ignored, which is probably the best thing to do since there are may possible attempts to change the text of that control, by using the code I gave to you.

CheckForIllegalCrossThreadCalls = false;






Re: Visual C# General Sample code problem: creating threads

bk13

Hello,

I have made the change, but I still have the problem that I mentioned earlier. There is no path for the new value created in the spawned thread to get to the text box. I tried to add a parameter to procedure UpdateBar and consequently to the delegate code. There is obviously someing I am missing as I get two errors, both associated with this line:

Invoke(d( new_value ) )

Without the argument I get a message about mismatch in arguments. With the argument the first error message says

The best overloaded method match for 'declaration' has some invalid arguments
and the other says
Argument '1': cannot convert from 'void' to 'System.Delegate'
I have checked the arguments and all are of the same type. The code is below. I have edited in comments as I understand what is going on. Please let me know if I need to change these comments. I have also added the text ERROR POINT as a comment at the offending line of code.

As I found in another thread, it does help to paste the code into an editor, the paste that into here. The process keeps some resemblense of formatting.



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadWinApp
{
public partial class Form1 : Form
{
// private Thread trd;

// Delegates have 3 parts
// 1) the type of signature of the method it can point to
// 2) The reference use to call a method
// 3) The method that is referenced and runs when called via the delegate
// I think this if part 1 of the delegate concept.
public delegate void UpdateDel( int new_value );

// this procedure will update the progress bar in the window.
// this is part 3 of the delegate construct. The procedure that will
// run when the delegate is called (but calling is named invoke)
private void UpdateBar( int new_value )
{
// If this procedure was called from a thread that is not where
// the procedure was declared/created (right wording ), then
// InvokeRequired will be true meaning that this procedure cannot
// be directly called. It must be called via a delegate.
if (InvokeRequired)
{
// This procedure appears to be assigning itself as the delegate.
// I suspect that the Invoke(d) essentially causes the UpdateBar
// to be called from the original thread. In that event, the
// if statement will not be taken, and the progress bar will be
// udated.
// I don't understand what is going on here.
// this is part 2 of the delegate concept. A delegate named "d"
// is created and associated with the function that will eventually
// be called.
UpdateDel d = new UpdateDel(UpdateBar);

// Delegate invocation. Call the function using the delegate.
Invoke(d( new_value ) ); // << ERROR POINT <<
return;
}
// This is the statement we want to be executed to update the
// progress bar.
this.progressBar1.Value = new_value;
}

public Form1()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
}

// Give the button something to show it is an active component.
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("This is the main thread");
}

// this is the task to be spawned off. When the form is loaded
// function Form1_Load is called and it starts this function as
// a separated task. It will calculate a new value for the
// progress bar, update the prgress bar, then sleep for 0.2 seconds
// BUT: UpdateBar will not be running within the same thread as
// this function. That is handled elsewhere.
private void ThreadTask()
{
int stp;
int newval;
Random rnd = new Random();

while (true)
{
stp = this.progressBar1.Step * rnd.Next(-1, 2);
newval = this.progressBar1.Value + stp;

if (newval > this.progressBar1.Maximum)
newval = this.progressBar1.Maximum;
else if (newval < this.progressBar1.Minimum)
newval = this.progressBar1.Minimum;

UpdateBar( newval ); // change from frederikm
//this.progressBar1.Value = newval;

Thread.Sleep(100);
}
}

private void Form1_Load(object sender, EventArgs e)
{
Thread trd = new Thread(new ThreadStart(this.ThreadTask));
trd.IsBackground = true;
trd.Start();
}



}
}







Re: Visual C# General Sample code problem: creating threads

Lowendahl

The delegate is indeed an object that you create on your spawned (background) thread. That delegate will point to a method and then get's passed an scheduled for execution on the main thread.

This is done by using the Invoke method on a control of form (as shown in other examples in this thread). The invoke method will take that delegate object and pass it to the main thread and ask the main thread to execute it.






Re: Visual C# General Sample code problem: creating threads

Lowendahl

"The InvalidOperationException can be ignored, which is probably the best thing to do since there are may possible attempts to change the text of that control, by using the code I gave to you."

Ignoring this exception should not be a habit. The problem is wider then usual thread syncronization and includes the windows hwnd engine and the fact that windows sends messages to the windows/controls and trigger code execution like Paint. You should always execute code that change a control on the thread that created that control, so that thread can schedule your update together with other code running initiated by window messages.






Re: Visual C# General Sample code problem: creating threads

Lowendahl

Basically what you're doing is passing the result (not really since it's a void delegate, but you get the picture) of the delegate invocation to the Invoke method, wheras the Invoke method want the delegate object itself passed to it.

Doing this

Invoke( d( new_value ) )

will execute the delegate then pass the result to Invoke, you are looking for a solution that does this:

Invoke(d, new_value);

Which should send the delegate object to the main thread and tell it to execute it with the parameter provided.






Re: Visual C# General Sample code problem: creating threads

bk13

Well by golly, that works. Thank you.

That looks like command line arguments. I will go back to the web pages and see where I missed it.

I do have a remaining concern. My detached process/thread will collect data from UDP messages at about 10 Hz. There is a possiblity of collision when a message arrives while I am working with the data. To explain would clearly be thread drift. i will work that and start a new thread if needed. I have marked your reply as an answer and will mark a few others as helpful and maybe answer. (Can there be two answer posts, I shall see)






Re: Visual C# General Sample code problem: creating threads

bk13

Hello All,

I have created my Windows application that spawns a thread. The spawned thread generates test data and uses a delegate to get it back to the main task. The main task catches the data and updates its displays. Step 16 or so of my spiral development is now complete. Only a dozen (hundred ) or so to go. The next step, changing my spawned task to catch network messages should be relativly easy. This posting thread is one of the critical question threads that got me going.

Thank you all for your patience and help.