Re: Is this Threadsafe?

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



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
.



Relevant Pages

  • Re: Async callback vs events vs ?
    ... This seems to make life complicated and dangerous since there is still a lot I need to do with the information returned including updating the GUI, calling more methods, ... ... The only thing you probably need to really fix is the lack of a call to Control.Invokein your event handler. ... just pass your delegate instance as the state object to the call to BeginInvoke, and then retrieve that from the IAsyncResult.AsyncState property. ... The call to Control.Invoke() does the exact same check, and will simply invoke the delegate directly if InvokeRequired is false. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: CoBOL moved to OO
    ... of a list of file names' by using the Windows GUI and the keyboard alone ... > Alternatively write the collection elements to your text file with a Callback (see ... > invoke FileNames2 "new" returning os-Filenames ...
    (comp.lang.cobol)
  • Re: Async callback vs events vs ?
    ... I suppose I could use the IAsyncResult to pack this information in but - and here is where I lose the plot - all of this is still running under the thread from the threadpool as far as i can tell. ... This seems to make life complicated and dangerous since there is still a lot I need to do with the information returned including updating the GUI, calling more methods, ... ... -- Related to the above, there's no need to check the EndInvokeCalled property; your callback will only be called once per invocation, and you should write the code to only call EndInvokein that callback. ... The call to Control.Invoke() does the exact same check, and will simply invoke the delegate directly if InvokeRequired is false. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: best way to receive callbacks in a GUI from other threads
    ... If the mechanism you're using implies asynchronous behavior then I ... I have a GUI that needs to detail time taken to do jobs ... handing it a callback to call once the job has finished. ... via Invoke. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: GOBACK (was: Perform Thru/Go to vs. Perform - Compile Speed
    ... This means the overhead is not in _making_ a call, ... _receiving_ a call. ... ..I added two tests to INVOKE an OO method. ... is inherently slower, it will be because there's so much overhead on receiving a ...
    (comp.lang.cobol)