Re: a few issues with events

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance



not_a_commie wrote:
First, all over my code I have something like this:

if(dumbEvent != null)
dumbEvent(blah);

What's dumb about that is that the compiler or JIT engine should be
able to figure out if the thing is null or not and skip it.

If that were true, then we would never have to test for null. After all, the compiler or JIT engine should always be able to check if a thing is null and just not execute the code using the null reference.

Of course, this would lead to problems where code silently fails when a reference is null, in many cases simply not executing code that's very important to execute. Sure, it wouldn't crash...but the code would still be wrong and it would be much harder to find the problem.

Another
thing that's dumb about that is I'm always nervous that somebody will
disconnect the last event in between the "if" and the trigger. Calling
an event should be atomic and the coder should not have to worry about
that.

That it should. That is why, when you have an event that could be manipulated in a threaded code environment, you should always copy the event to a local variable before checking it for null and executing it. For example:

void OnRaiseSomeEvent()
{
EventHandler handler = theActualEvent;

if (handler != null)
{
handler(this, new EventArgs());
}
}

Second, dealing with WinForms, Control.Invoke (or BeginInvoke) lock on
"this". That's genius, considering Invoke comes in real handy when
you're not dealing with cross-thread issues ;-). No public class
should ever lock on "this". It's just not fair to the coder. Anybody
know if this is fixed with the Dispatcher in WPF?

If what is fixed?

First of all, you should never lock on "this" anyway. So it should not matter to you whether something else locks on "this". But beyond that, I have seen no evidence that Control.Invoke() _does_ lock on "this". I tried it myself. One thread waits on an event handle, then enters a lock(this) and then sets a second event handle inside the lock. The other thread calls Invoke() with code that sets the first event handle then waits on the second event handle.

If what you said was true, that code should deadlock. It should get stuck in the second thread waiting for the event handle to be set, while the first thread gets stuck trying to get the lock on "this".

But it doesn't. The code executes just fine.

So, while I'd agree that using "this" for the lock() statement isn't a very good idea, I've seen no evidence that Control.Invoke() does in fact do that.

If you have some reason to believe it does, perhaps you could be more specific about why you believe that.

Another issue with events. According to the documentation, Thread.Join
should continue to process messages. It doesn't.

It does. But only in the very specific way that the documentation describes.

In particular, Join() is documenting as continuing to process COM and SendMessage() messages. These are very specific kinds of messages, in which a thread in an alertable wait state can be co-opted to execute code to handle messages coming from other threads.

This is not the same situation as normal window message queues, which AFAIK is what is actually used for things like Control.Invoke(). This normal mechanism depends on the thread actively calling a function like GetMessage() to poll for messages and process them. In a .NET application, the Application.Run() method generally sets up the message pump required for this. If you never call Application.Run() or if the thread is stuck on Join(), it won't be able to execute the message pump and something like Control.Invoke() won't work.

If you want a thread blocked on Join() to process messages, you will probably have to use p/invoke to get at the SendMessage() function directly, and also override the WndProc method in your Form class so that you can receive the message sent by SendMessage().

Not that I'd suggest that's actually a good idea. There are better ways, more in line with the standard .NET architecture, to deal with synchronizing threads and allowing for the normal .NET message pump to work correctly. But you could do it that way.

Pete
.



Relevant Pages

  • Re: Fwd: [HP3000-L] Max Extents and Extents size from intrinsic FFILEINFO
    ... EXECUTE: FALSE ... APPEND: FALSE ... LOCK: FALSE ... * To join/leave the list, search archives, change list settings, * ...
    (comp.sys.hp.mpe)
  • Re: per cpun+ spin locks coexistence?
    ... You cannot switch to another processor in schedule_work, ... structures to be freed and then have to protect it by a global lock. ... Two CPUs doing fdtable free operations simultaneously will ... schedule_workis guaranteed to execute the work queue at least once, ...
    (Linux-Kernel)
  • Re: windows (vb.net 1.1) service - threading issue
    ... new thread seems to try and also tries to execute Timer1.Stop. ... End Sub ... SyncLock in this way? ... enters the lock, and never exits - then yes, you could deadlock. ...
    (microsoft.public.dotnet.languages.vb)
  • Re: [patch] SMP alternatives
    ... when LOAD microinstruction is executed. ... LOCK ADD, EDX ... locked and ADD and STORE can't execute because they're waiting for LOAD ...
    (Linux-Kernel)