C# threading, events and main thread.

D

djdouma

I've been working on this one for a couple of days, and am completly
at my wits end. Is there some method for executing a function or
event in the main thread, when called from a 'worker' thread? I
understand how it works in the Windows forms world, but what about an
application with no GUI?

I provided example code and the output below. What I'm looking for is
to have the prog_ShowPopUpEvent method executed by the main thread.

Thanks!

Output:
MAIN THREAD : Sleeping for 1 second
MAIN THREAD : Sleeping for 1 second
MAIN THREAD : Sleeping for 1 second
MAIN THREAD : Sleeping for 1 second
MAIN THREAD : Sleeping for 1 second
TIMER THREAD : timer elapsed
TIMER THREAD : fire show pop up event
TIMER THREAD : show pop up event fired
Main thread exiting.

Code:
using System;
using System.Threading;

namespace ConsoleApplication1
{
public class Program
{
private bool _running = false;
private event EventHandler ShowPopUpEvent;

[STAThread]
public static void Main()
{
Program prog = new Program();
prog.Run();
}

private void Run()
{
this.ShowPopUpEvent += new
EventHandler(prog_ShowPopUpEvent);
Thread.CurrentThread.Name = "MAIN THREAD";

System.Timers.Timer checksTimer = new
System.Timers.Timer();

//Elapse every 5 seconds
checksTimer.Interval = 5000;
checksTimer.Elapsed +=new
System.Timers.ElapsedEventHandler(checksTimer_Elapsed);
checksTimer.Enabled = true;

this._running = true;

do
{
Console.WriteLine("{0} : Sleeping for 1 second",
Thread.CurrentThread.Name);
Thread.Sleep(1000);
}
while (this._running);
Console.WriteLine("Main thread exiting.");
}

private void prog_ShowPopUpEvent(object sender, EventArgs e)
{
Console.WriteLine("{0} : show pop up event fired",
Thread.CurrentThread.Name);
this._running = false;
}

void checksTimer_Elapsed(object sender,
System.Timers.ElapsedEventArgs e)
{
if (Thread.CurrentThread.Name == null)
Thread.CurrentThread.Name = "TIMER THREAD";

Console.WriteLine("{0} : timer elapsed",
Thread.CurrentThread.Name);

//Perform a bunch of checks
if (true == false)
{
}
else
{
//Show the popup window
OnShowPopup();
}
}

private void OnShowPopup()
{
if (ShowPopUpEvent != null)
{
Console.WriteLine("{0} : fire show pop up event",
Thread.CurrentThread.Name);
ShowPopUpEvent(this, new EventArgs());
}
}
}
}
 
P

Peter Duniho

I've been working on this one for a couple of days, and am completly
at my wits end. Is there some method for executing a function or
event in the main thread, when called from a 'worker' thread?

Yes. Use the Control.Invoke() method.

I don't know what version of Visual Studio you're using, if any, but I'm
using VS 2005 and if I tried to execute the code you posted, I'd get the
"cross-thread call" MDA exception, with a clickable link to a help topic
that provides very nice details regarding how to do this.

Pete
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
Yes. Use the Control.Invoke() method.

There are no controls to invoke in this case though - it's a console
application.
I don't know what version of Visual Studio you're using, if any, but I'm
using VS 2005 and if I tried to execute the code you posted, I'd get the
"cross-thread call" MDA exception, with a clickable link to a help topic
that provides very nice details regarding how to do this.

No, you wouldn't - that applies to Windows Forms, not console
applications.
 
J

Jon Skeet [C# MVP]

djdouma said:
I've been working on this one for a couple of days, and am completly
at my wits end. Is there some method for executing a function or
event in the main thread, when called from a 'worker' thread? I
understand how it works in the Windows forms world, but what about an
application with no GUI?

You'd need to have your own equivalent of the message pump - basically
the main thread would just have to be waiting to be given work to do.
You can't interrupt a running thread to give it a different task.
 
P

Peter Duniho

No, you wouldn't - that applies to Windows Forms, not console
applications.

Are you trying to tell me that I should not be trying to answer questions
after staying up almost all night with a sick kid?

Sheesh...picky, picky.

(Yes, I completely missed the fact that this is a console
application...sorry)
 
B

Ben Voigt [C++ MVP]

Jon Skeet said:
You'd need to have your own equivalent of the message pump - basically
the main thread would just have to be waiting to be given work to do.
You can't interrupt a running thread to give it a different task.

So the key question is, what is the main thread doing when you want to give
it a function to execute? Can you have it periodically poll a list of
delegates (don't forget locking, or use a thread-safe linked list)?
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
Are you trying to tell me that I should not be trying to answer questions
after staying up almost all night with a sick kid?
LOL.

Sheesh...picky, picky.

(Yes, I completely missed the fact that this is a console
application...sorry)

If I had to pay someone every time I'd come up with a bad answer for
whatever reason, I'd be on the street...
 
P

Peter Duniho

I've been working on this one for a couple of days, and am completly
at my wits end. Is there some method for executing a function or
event in the main thread, when called from a 'worker' thread? I
understand how it works in the Windows forms world, but what about an
application with no GUI?

For what it's worth, now that I have been directed back onto the correct
track...

Can you explain in more detail _why_ you want the handling of the event to
occur on the main thread? The reason this is such a big deal with a Form
is because of the restrictions Windows has with respect to windows and
their relationship to the thread that created a window. But as far as I
know, there's not a similar issue with the console output.

(In my defense, it's this lack of an issue with respect to console
applications, as well as the "ShowPopUp" name of your event handler, that
made me assume you were talking about Forms even though you specifically
said you weren't).

Pete
 
B

Ben Voigt [C++ MVP]

Jon Skeet said:
If I had to pay someone every time I'd come up with a bad answer for
whatever reason, I'd be on the street...

So would I. In fact, isn't that the true meaning of "MVP"?
 
D

djdouma

So the key question is, what is themainthreaddoing when you want to give
it a function to execute? Can you have it periodically poll a list of
delegates (don't forget locking, or use athread-safe linked list)?





- Show quoted text -

I suppose the main thread could poll a list of delegates to see if it
has work to do. Would you be able to provide a sample of this? Would
the delegate list just be using an ArrayList or a typed List<T>? I
was looking for similar functionality to the Invoke / BeginInvoke used
in Windows Forms. The reason for the do while with a sleeping thread
is just so the application doesn't exit. :D The timer checks if
certian conditions have exist (Certian reg values to exist, files to
exist, etc), and notify the main thread. The main thread will then
respond according to the condition that was met. In some cases, it
may need to display a pop-up, in others, it may need to start a
process.
 
B

Ben Voigt [C++ MVP]

djdouma said:
I suppose the main thread could poll a list of delegates to see if it
has work to do. Would you be able to provide a sample of this? Would
the delegate list just be using an ArrayList or a typed List<T>? I
was looking for similar functionality to the Invoke / BeginInvoke used
in Windows Forms. The reason for the do while with a sleeping thread
is just so the application doesn't exit. :D The timer checks if
certian conditions have exist (Certian reg values to exist, files to
exist, etc), and notify the main thread. The main thread will then
respond according to the condition that was met. In some cases, it
may need to display a pop-up, in others, it may need to start a
process.

Use an Event to wake the main thread after adding to the list, instead of
polling.

I would certainly recommend using a generic LinkedList<T>. ArrayList is the
best that could be done in C# 1.0, since C# 2.0 came out the generic
collections are better in every way. Or you could just use a delegate
variable with the += operator.

Surround all access to the delegate list with a lock block for
thread-safety... you can lock on the list if you use a LinkedList, or on
typeof(MyMainClass) if using a static delegate variable.
 
P

Peter Duniho

I suppose the main thread could poll a list of delegates to see if it
has work to do. Would you be able to provide a sample of this? Would
the delegate list just be using an ArrayList or a typed List<T>? I
was looking for similar functionality to the Invoke / BeginInvoke used
in Windows Forms.

Ben has given good suggestions for how to implement this yourself.
There's nothing built in to .NET that provides for this directly, a la
Invoke().
The reason for the do while with a sleeping thread
is just so the application doesn't exit. :D The timer checks if
certian conditions have exist (Certian reg values to exist, files to
exist, etc), and notify the main thread. The main thread will then
respond according to the condition that was met. In some cases, it
may need to display a pop-up, in others, it may need to start a
process.

In addition to what Ben wrote, regarding implementing a delegate queue,
your reply begs the question: if all the main thread is doing is waiting
for some other thread to do work, why not just do the work on the main
thread?

Basically, we can answer the question (and Ben has) of how to accomplish
the very specific goal stated (have one thread pass a delegate to another
thread for execution). But it still appears that there's no need to do
that. It's not usually necessary for a given piece of code to execute on
a particular thread, and it's not clear what it is that the main thread in
your application is doing that prevents it from simply being the thread to
do whatever the other thread is doing anyway.

It seems to me that there are two open questions yet:

1) Why can't the code running on the worker thread simply be executed
in the main thread?

2) Why can't the code that you want executed on the main thread just
be executed in the worker thread?

You don't have to answer these question here, of course. But if you want
the best advice, you should. And at a minimum, you should at least
consider them with respect to the design of your code, because on the face
of it there are some odd things about the design of your code, at least
based on the small peek we have gotten of it.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top