beginners question about UI threading


C

Colin Peters

I need some tips on how to realize a particular functionality in c#.
I’ve left out any c# nomenclature because I don’t want to muddy the
water by misusing terms.

I have a windows service that implements its business logic in a worker
thread. This allows the main thread of the service to react to stop and
start messages quickly whilst the worker thread polls occasionally to
see if it ought to stop.

So, just to recap, that makes two threads; a message pump (MP) thread
that implements the bare bones of a windows service and a worker thread
which does the real work. Let’s say that the “real work” involves
checking hardware periodically and updating a db with results. It runs
in an endless loop until the MP thread sets its “exit” bool.

Now, I want to add a component to the mix. It is periodically polling
another DB for updates and needs to inform my service when interesting
changes have taken place. The polling rate is outside my concern. The
component will call a callback function when a change is detected. Since
the component is to function fairly autonomously I guess it runs in its’
own thread (call it Thread3), probably a MP thread because it will have
to handle timer messages.

The question is: How can I detect when the callback is called? Is it
possible to execute the callback in a thread other than Thread3?

I imagine the pseudo code in my logic thread to look something like this:

Logic::Start()

{

M_Control = new M_Control();

M_Control.SetCallBack(SomethingHappened);

M_Control.StartYourPollingLogic();

....

While(!exit)

{

//Do other stuff

If(bSomething)

{

// react to this then set Boolean back to false

}



}

....

}



Logic::SomethingHappened()

{

bSomething = true;

}


Setting aside the race condition on bSomething, how can I pass to the
M_Control the address of the function I want it to call?

I'm not after a complete solution, just some hints as to what namespaces
or topics I ought to look at.

Thanks in advance

Colin
 
Ad

Advertisements

P

Peter Duniho

[...]
Now, I want to add a component to the mix. It is periodically polling
another DB for updates and needs to inform my service when interesting
changes have taken place. The polling rate is outside my concern. The
component will call a callback function when a change is detected. Since
the component is to function fairly autonomously I guess it runs in its’
own thread (call it Thread3), probably a MP thread because it will have
to handle timer messages.

The question is: How can I detect when the callback is called? Is it
possible to execute the callback in a thread other than Thread3?
My first concern is your subject text, "...about UI threading". AFAIK, a
service and a UI are mutually exclusive. So it's unclear to me what you
mean by "UI threading".

As far as the question itself goes, you can invoke a delegate (i.e.
callback) on a specific thread in a variety of ways:

-- Where there is a Forms or WPF message pump, you can use the normal
Forms or WPF mechanisms (e.g. Control.Invoke() for Forms, )
-- Alternatively, in Forms or WPF you can use a SynchronizationContext
as an abstraction away from the GUI-specific mechanisms to accomplish the
same thing

Absent specific support, you can implement support yourself. IMHO the
simplest way is to just create a producer/consumer queue, where the thread
that should be executing the delegate is the consumer, and the threads
that want the delegate to be executed are the producers. Alternatively,
you can write your own SynchronizationContext sub-class that does the
equivalent.

I believe that in the past, there have been threads in this newsgroup
regarding producer/consumer delegate queues, so Google Groups may be able
to turn up useful information, including possibly one or more
implementation examples.

Pete
 
P

Peter Duniho

[...]
-- Where there is a Forms or WPF message pump, you can use the
normal Forms or WPF mechanisms (e.g. Control.Invoke() for Forms, )
Sorry...meant to include the System.Windows.Threading.Dispatcher class
here (the WPF version of Control.Invoke()).
 
C

Colin Peters

Hi Peter,

Thanks for the reply.

When I say UI thread, what I mean is a thread with a message pump. I
guess my question is: how can you create a thread with a message pump. A
bit more research has shown that you can't. And that message posting
isn't really in the c# paradigm. However, I can implement something
similar through a regular worker thread and a shared queue, it seems.

Thanks for your assistance.

Peter said:
[...]
Now, I want to add a component to the mix. It is periodically polling
another DB for updates and needs to inform my service when
interesting changes have taken place. The polling rate is outside my
concern. The component will call a callback function when a change is
detected. Since the component is to function fairly autonomously I
guess it runs in its’ own thread (call it Thread3), probably a MP
thread because it will have to handle timer messages.

The question is: How can I detect when the callback is called? Is it
possible to execute the callback in a thread other than Thread3?

My first concern is your subject text, "...about UI threading". AFAIK,
a service and a UI are mutually exclusive. So it's unclear to me what
you mean by "UI threading".

As far as the question itself goes, you can invoke a delegate (i.e.
callback) on a specific thread in a variety of ways:

-- Where there is a Forms or WPF message pump, you can use the
normal Forms or WPF mechanisms (e.g. Control.Invoke() for Forms, )
-- Alternatively, in Forms or WPF you can use a
SynchronizationContext as an abstraction away from the GUI-specific
mechanisms to accomplish the same thing

Absent specific support, you can implement support yourself. IMHO the
simplest way is to just create a producer/consumer queue, where the
thread that should be executing the delegate is the consumer, and the
threads that want the delegate to be executed are the producers.
Alternatively, you can write your own SynchronizationContext sub-class
that does the equivalent.

I believe that in the past, there have been threads in this newsgroup
regarding producer/consumer delegate queues, so Google Groups may be
able to turn up useful information, including possibly one or more
implementation examples.

Pete
 
P

Peter Duniho

Hi Peter,

Thanks for the reply.

When I say UI thread, what I mean is a thread with a message pump. I
guess my question is: how can you create a thread with a message pump. A
bit more research has shown that you can't.
In unmanaged code, you can have a message-only window and run a message
pump with that. I admit, I don't actually know what the equivalent of
that is in .NET, if any.
And that message posting isn't really in the c# paradigm. However, I can
implement something similar through a regular worker thread and a shared
queue, it seems.
If all you need is to execute delegates on a particular thread, IMHO the
producer/consumer approach seems fine.

That said, you should make sure you really need to execute the delegates
on a particular thread. Usually when that happens, there's affinity to
that thread for a particular reason, and in Windows that reason often
involves some kind of messaging issue, in which case there'd already be a
message queue for you to use.

I don't know much about writing services, but it's possible that you've
already got a way to invoke a delegate on the service's main
message-handling thread.

Pete
 
B

Ben Voigt [C++ MVP]

Peter said:
In unmanaged code, you can have a message-only window and run a
message pump with that. I admit, I don't actually know what the
equivalent of that is in .NET, if any.
NativeWindow makes a pretty good message-only window. And Application.Run
is the message pump.
If all you need is to execute delegates on a particular thread, IMHO
the producer/consumer approach seems fine.
Control.BeginInvoke is the .NET way to do this.
 
Ad

Advertisements

P

Peter Duniho

[...]
If all you need is to execute delegates on a particular thread, IMHO
the producer/consumer approach seems fine.
Control.BeginInvoke is the .NET way to do this.
If you have a Forms application. If not, other approaches are "necessary"
(notwithstanding the option of essentially making a program a Forms
application when it otherwise would not need to be :) ).
 
B

Ben Voigt [C++ MVP]

Peter said:
[...]
If all you need is to execute delegates on a particular thread, IMHO
the producer/consumer approach seems fine.
Control.BeginInvoke is the .NET way to do this.
If you have a Forms application. If not, other approaches are
"necessary" (notwithstanding the option of essentially making a
program a Forms application when it otherwise would not need to be :)
).
oops, I was thinking that NativeWindow provided a BeginInvoke
implementation. It doesn't. So NativeWindow and PostMessage would be a
lighter-weight way to do it, assuming you need a message loop because other
components using message-only windows on the thread require it (this
includes all COM and ActiveX objects). If there are no other components on
the thread, then a WaitHandle and queue is the leanest way to solve the
problem.

MsgWaitForMultipleObjects and PostThreadMessage is a good option if you
don't want to write your own queue.
 
P

Peter Duniho

oops, I was thinking that NativeWindow provided a BeginInvoke
implementation. It doesn't. So NativeWindow and PostMessage would be a
lighter-weight way to do it, assuming you need a message loop because
other
components using message-only windows on the thread require it (this
includes all COM and ActiveX objects).
Right. And like I said, while I'm not that familiar with services, I have
the impression that they have a sort of message queue somewhere, because
that's how the OS informs it of startup, shutdown, etc.
If there are no other components on
the thread, then a WaitHandle and queue is the leanest way to solve the
problem.
Or a Monitor and a queue. I don't know the exact performance
characteristics of each, but I doubt Monitor is heavier-weight than a
WaitHandle.
MsgWaitForMultipleObjects and PostThreadMessage is a good option if you
don't want to write your own queue.
Yup, that would be fine too. The main problem being that it's not managed
code.

Pete
 
C

Colin Peters

So, just a quick note to tell you what I did in the end, which seems to
work as well as it needs to.

My external control (the one that is polling a DB and informing me when
something important happens) runs its own polling thread. It calls back
through a delegate that my hosting component supplies. Naturally the
callback is within the thread of the external control. However the
implementation of the delegate is to write an item to a thread safe
queue. The consumer (in its own thread) then picks up the item from the
queue and runs the real work in the consumer thread.

BTW you're right about a service having a message pump. The thing is I
can't really put code into that thread because a) I want the service to
react speedily to start/stop requests, and b) the whole logic of the
program must run from either a service, or from a console app (to make
debuging easier, if nothing else).

Thanks for both your replies; often the real problem is finding the
right expressions to describe the issue without polluting the debate
with technology specific terms.
 
Ad

Advertisements

B

Ben Voigt [C++ MVP]

Peter said:
Right. And like I said, while I'm not that familiar with services, I
have the impression that they have a sort of message queue somewhere,
because that's how the OS informs it of startup, shutdown, etc.
Services don't (must not) pump messages on the main thread, and probably
shouldn't use window messages on that thread at all.

The Service Control Manager has some sort of event loop, which calls the
service entry point. The service entry point always needs to return
quickly, the SCM has zero tolerance of service entry points running a
message pump or using blocking I/O calls.
 
Ad

Advertisements


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

Similar Threads


Top