Re: Is this Threadsafe?
- From: "Peter Duniho" <NpOeStPeAdM@xxxxxxxxxxxxxxxx>
- Date: Wed, 22 Apr 2009 11:49:48 -0700
On Wed, 22 Apr 2009 09:38:05 -0700, Gina_Marano <ginalster@xxxxxxxxx> wrote:
Ok, can I get a little help here since I have shown to be threadsafe
inadequate... :)
Don't be so hard on yourself..."inexperienced" is, I think, a nicer way to describe it. After all, "inexperienced" is something you can simply learn yourself out of. :)
I have used Control.Invoke() in the past but that was to just update
the GUI.
Not sure how to use Control.Invoke() with different functionalities
acting on the same object.
It's pretty much the same. There's one minor exception (returning a value from an invoked method), but even that can be avoided if you want.
Do I make one super delegate with a set of params/flags to specify
what I want to do?
I don't know what a "super delegate" is anyway, but no...nothing like that.
Three functionalities that I need:
1) add an item to the dictionary from the GUI
Note that this already happens on the GUI (your button click handler, right?). So, you don't need to use Invoke() for this, assuming you know for sure the "add" method is always executed from the GUI thread.
2) check to see if the is in the dictionary (from a thread)
I assume this is your ContainsXMLFileName() method? This is the one that returns a value, making it the most complicated part (and even at that, not all that complicated).
For simplicitly, let's assume that we're keeping the same methods you had in your SpecXMLFileNameCache class, but instead we'll just put them in the FormMain class. Then in the FormMain class, that method can look like this:
public bool ContainsXMLFileName(string aFileName)
{
return (bool)Invoke((Func<bool>) delegate
{
return _SpecXMLFileNameCache.Contains(aFileName);
});
}
Notes:
-- Invoke() always returns an Object, which has to be cast back to the actual return type of the invoked method.
-- I've switched your code to use Contains() instead of TryGetValue(); the latter wasn't useful, because you never did anything with the retrieved value.
-- You could separate the call to Contains() into a different method, but because it's specifically tied to this method, I prefer to use an anonymous method.
-- The Invoke() method uses the type "Delegate" as the argument type for the delegate, preventing the compiler from making any inference as to the delegate type to instantiate. Typically you'd cast the anonymous method to "MethodInvoker" for the most common uses of Invoke(), but in this case we want to return a value, so we need a delegate type compatible with the anonymous method used here. You could declare a custom delegate type, but .NET 3.5 has the Func<T> generic delegate type we can use, so I used that instead.
-- If you call this method while already on the GUI thread, in theory the call to Invoke() is useless overhead. But, it's not very much overhead and doesn't interfere with the correct operation of the code. So my preference is to just always call Invoke(), whether needed or not, to keep the code simpler.
An alternative to the above syntax would be to use a "captured" variable to store the result in the invoked anonymous method, and then retrieve the value from the variable after the call to Invoke():
public bool ContainsXMLFileName(string aFileName)
{
bool fRet;
Invoke((MethodInvoker) delegate
{
fRet = _SpecXMLFileNameCache.Contains(aFileName);
});
return fRet;
}
This is mainly a syntactical variation. It avoids the boxing/unboxing of the "bool" value, but there's extra overhead for the captured variable, so it's basically a wash in terms of overhead (though, actually...in these examples, the method argument winds up captured too, so the capturing overhead is already incurred one way or the other). It's just about what you find more readable/maintainable (e.g., in a different situation where you're just putting the returned value into a local variable, it might be more readable to just capture that local variable and have the invoked method do the assignment).
3) update the dictionary value from a thread (same thread as #2)
This scenario is (I'm guessing) more like what you're already used to doing with Invoke(). That is, you're just executing code. This can look like this:
public void UpdateXMLFileNameStatus(string aFileName)
{
Invoke((MethodInvoker)delegate
{
if (_SpecXMLFileNameCache.ContainsKey(aFileName))
{
_SpecXMLFileNameCache[aFileName] = true;
}
});
}
2 and 3 will never be concurrent.
Even if they are, the above will ensure proper synchronization between the two. :) If you want to guarantee synchronization between all three operations, just apply the same technique to the first (adding something to the dictionary).
As I mentioned, there definitely is additional overhead involved in this technique. The Invoke() method itself involves overhead, and no matter how you invoke the method, there will be some additional overhead getting data into and out of the method, as compared to simply using a "lock()" statement. But in this context, it seems very unlikely to me that the overhead has any significance at all, and the code is IMHO simplified a bit (especially as compared to the code you originally posted).
Pete
.
- Follow-Ups:
- Re: Is this Threadsafe?
- From: Ben Voigt [C++ MVP]
- Re: Is this Threadsafe?
- References:
- Is this Threadsafe?
- From: Gina_Marano
- Re: Is this Threadsafe?
- From: Arne Vajhøj
- Re: Is this Threadsafe?
- From: Peter Duniho
- Re: Is this Threadsafe?
- From: Gina_Marano
- Re: Is this Threadsafe?
- From: Gina_Marano
- Is this Threadsafe?
- Prev by Date: Re: Copy SecureString with Length
- Next by Date: Re: Please help me with some pointer work -- thanks!
- Previous by thread: Re: Is this Threadsafe?
- Next by thread: Re: Is this Threadsafe?
- Index(es):
Relevant Pages
|