WCF "Begin" call is *sometimes* blocking ?

O

Omatase

I'm posting this here although I have already posted it on the MSDN
forums because noone seems to visit those forums.

Thanks for any help you can give!

I have a question mark at the end of the title because I can't quite
tell what is happening, but although I have Begin* and End* calls
littered throughout my code (I am doing a Silverlight app) I am only
having an issue with one call in particular.

The problem I am having is I call BeginCreateTeam on my WCF service
and wait for the AnonymousMethod that I provided in the AsyncCallback
to execute. While I am waiting I execute this code:

while(createTeamSuccessful == null)
{
Thread.Sleep(1000);
}


createTeamSuccessful is a bool that is populated when the
AsyncCallback AnonymousMethod is executed.

Although I use this pattern all over the place in my Silverlight code,
it isn't working in this case for some reason. Below is a more
complete picture of the code I am using.

_popup is a class that displays some UI elements. When the UI element
is closed, OnPopupClosed is called (shown below this code element)

_popup = new InputPopup(CherubGameReference);


_popup.OnPopupClosed += ((a) =>
{
if (!string.IsNullOrEmpty(a.Trim()))
{
_teamName = a.Trim();

if(createTeam(_teamName))
{
CherubGameReference.RefreshAccountDetails();

CherubGameReference.ShowNotification(string.Format("New
team ({0}) created.", _teamName));

Drop(GameStateData.ManageTeamsMenu, null);
}
else
{
_finishButton.Enabled = true;

Form.Active = true;
}
}
else
{
_finishButton.Enabled = true;

Form.Active = true;
}

});


_finishButton.OnClick += ((a) =>
{
_finishButton.Enabled = false;

Form.Active = false;


_popup.ShowPopup("Please enter a name for your new team");
});

ok is a button in the popup UI element.

ok.OnClick += ((a) =>
{
if(OnPopupClosed != null)
{
OnPopupClosed.Invoke(_textBox.Text);

Hide();
}

});

here is the "createTeam" method for completeness, a portion of this
code is already shown above

private bool createTeam(string teamName)
{
bool? createTeamSuccessful = null;

NetworkAbstractionLayer.CreateTeam((from a in _selectedCharacters
select a).ToList(), teamName,
(a) => { createTeamSuccessful = a; });

while (createTeamSuccessful == null)
{
Thread.Sleep(1000);
}

return createTeamSuccessful.GetValueOrDefault();
}

"NetworkAbstractionLayer" is a static class that keeps a single
instance to the WCF proxy open and available to the entire Silverlight
application and is responsible for handing the call off to the layer
that calls BeginCreateTeam and EndCreateTeam.

I have tried removing the static class as a step in the process
without success.

What I see happening is the Silverlight app hangs when the createTeam
method is called and that the code never leaves the while loop in the
immediately above code block. If I manually move execution below the
while loop then the AsyncCallback code is magically called!

One anomaly that I see occurring that doesn't look right is when I
look at the "Threads" window in VS when I am debugging in the sections
of code where I am doing any of the following:

* Invoking the OnPopupClosed event
* Handling the OnPopupClosed event
* Executing the BeginCreateTeam WCF call
* Handling the BeginCreateTeam AsyncCallback

It shows the current executing thread is "Main Thread". Since the
above items were all within an AnonymousMethod I expected to see the
thread executing on a thread other than "Main Thread" which is how it
seems to work everywhere else I am using this asynchronous pattern.

Appreciate any help!

--edit 01/09/10 8:26 AM--

Here is some more information I just learned about the problem:

Here is the actual code where Begin and End are handled:

public void CreateTeam(List<Character> characters, string teamName,
Action<bool> createTeamCallback)
{
_client.BeginCreateTeam(SessionManager.SessionId,
characters.ToArray(), teamName, ((a) =>
{
GameResponse returnedFromServer = ((ServiceClient)
a.AsyncState).EndCreateTeam(a);

if (createTeamCallback != null && returnedFromServer != null
&& returnedFromServer.ReturnValue != null)
{
createTeamCallback.Invoke((bool)
returnedFromServer.ReturnValue);
}

}), _client);
}

I just discovered after putting a breakpoint in my WCF server code
that although the debugger steps passed this block of code before
entering my while loop (I see the yellow highlight the entire block in
this method and then continue on). The CreateTeamMethod doesn't
actually execute on the server side unless I manually (in the
debugger) exit the while loop. ... Strange
 
P

Peter Duniho

Omatase said:
I'm posting this here although I have already posted it on the MSDN
forums because noone seems to visit those forums.

Thanks for any help you can give!

Unfortunately, without a concise-but-complete code example, including
the implementation for the BeginCreateTeam() method, it's not possible
to know what's going on.

However, there are definitely some red flags:
[...]
while(createTeamSuccessful == null)
{
Thread.Sleep(1000);
}


createTeamSuccessful is a bool that is populated when the
AsyncCallback AnonymousMethod is executed.

Although I use this pattern all over the place in my Silverlight code,

This is scary. The above pattern is bad enough used once, but for it to
be common practice for you is awful. That kind of polling is needless
and inefficient. Just use a blocking mechanism so the thread doesn't
have to do anything until something actually happens.

It will take a little more code (unless you write a helper to
encapsulate it), but the program will run a lot better. For example:

private bool createTeam(string teamName)
{
bool? createTeamSuccessful = null;
object objSync = new object();

NetworkAbstractionLayer.CreateTeam(
(from a in _selectedCharacters
select a).ToList(),
teamName,
(a) =>
{
lock (objSync)
{
createTeamSuccessful = a;
Monitor.Pulse(objSync);
}
});

lock (objSync)
{
while (createTeamSuccessful == null)
{
Monitor.Wait(objSync);
}
}

return createTeamSuccessful.GetValueOrDefault();
}

Another big problem is that there's no way to make local variables
"volatile", and for inter-thread use of a variable, you need volatile or
synchronized access to the variable.

It's _possible_ that's your actual problem. Lacking volatile semantics,
your anonymous method may in fact be executing but setting the variable
isn't visible in the other thread. Hard to say without a proper code
example. But if that's the problem, then doing the synchronization
correctly, as above, would fix that problem too (using the Monitor class
causes the necessary memory fence semantics to occur to ensure that
variables are up-to-date).
[...]
It shows the current executing thread is "Main Thread". Since the
above items were all within an AnonymousMethod I expected to see the
thread executing on a thread other than "Main Thread" which is how it
seems to work everywhere else I am using this asynchronous pattern.

An anonymous method does not in and of itself imply execution in a
different thread.

As far as the more general issue goes, I don't know much about WCF at
all, but is it possible that WCF handles threading issues via APC or COM
messages, or something like that? If so, then for asynchronous activity
to work properly, it would be critical to not block your main processing
thread without using a technique that allows for message pumping. If
this is the case, then again…it's possible that using a proper
synchronization technique instead of looping might fix it (my
recollection is that Thread.Sleep() does not in fact allow for message
pumping in the same thread, but that WaitHandle and Monitor both do).

Of course, it all begs the question: if you just want your thread to
block until the operation has completed, why use an asynchronous API at
all? Just use the synchronous version and be done with it.

Even posting in a WCF- or Silverlight-specific group, you really should
be posting a concise-but-complete code example. But for something
off-topic like that there, such an example is doubly important.
Preferably, it should not require the use of WCF or Silverlight at all,
because otherwise we wind up having to figure out how to enable and use
those technologies in a project just to reproduce the issue.

Pete
 
P

Peter Duniho

Peter said:
[...]
It will take a little more code (unless you write a helper to
encapsulate it),

As an example of such a helper class:

struct WaitingValue<T>
{
private T? _t;
private readonly object _objLock = new object();

public T Value
{
get
{
lock (_objLock)
{
while (_t == null)
{
Monitor.Wait();
}
}
return (T)_t;
}

set
{
lock (_objLock)
{
_t = value;
Monitor.Pulse(_objLock);
}
}
}
}

…which you can then use like this:

private bool createTeam(string teamName)
{
WaitingValue<bool> createTeamSuccessful =
new WaitingValue<bool>();

NetworkAbstractionLayer.CreateTeam(
(from a in _selectedCharacters
select a).ToList(),
teamName,
(a) =>
{
createTeamSuccessful.Value = a;
});

return createTeamSuccessful.Value;
}
[...]
As far as the more general issue goes, I don't know much about WCF at
all, but is it possible that WCF handles threading issues via APC or COM
messages, or something like that? If so, then for asynchronous activity
to work properly, it would be critical to not block your main processing
thread without using a technique that allows for message pumping. If
this is the case, then again…it's possible that using a proper
synchronization technique instead of looping might fix it (my
recollection is that Thread.Sleep() does not in fact allow for message
pumping in the same thread, but that WaitHandle and Monitor both do). [...]

I notice that this article confirms the above:
http://blogs.msdn.com/cbrumme/archive/2003/04/17/51361.aspx

Calling Thread.Sleep() does not allow for message pumping, but
WaitHandle and Monitor both do.

Pete
 
P

Peter Duniho

Peter said:
Peter said:
[...]
It will take a little more code (unless you write a helper to
encapsulate it),

As an example of such a helper class: [...]

Sorry, at the last minute I decided, unwisely, to make the type a
struct. The code I posted won't work as written, because you can't have
field initializers in a struct. Just change "struct" back to "class"
and it should be fine.

The code could be contorted to allow the type to be a struct, but IMHO
it's probably not worth the trouble.

Pete
 
O

Omatase

Peter said:
Peter said:
[...]
It will take a little more code (unless you write a helper to
encapsulate it),
As an example of such a helper class: [...]

Sorry, at the last minute I decided, unwisely, to make the type a
struct.  The code I posted won't work as written, because you can't have
field initializers in a struct.  Just change "struct" back to "class"
and it should be fine.

The code could be contorted to allow the type to be a struct, but IMHO
it's probably not worth the trouble.

Pete

Thanks for your help so far. I have implemented your suggestions using
the helper class as you showed. I did however have to modify a few
things to get it to compile. It looks like this now:

public class WaitingValue<T>
{
private T _t;
private readonly object _objLock = new object();

public T Value
{
get
{
lock (_objLock)
{
while (_t == null)
{
Monitor.Wait(_objLock);
}
}
return (T)_t;
}

set
{
lock (_objLock)
{
_t = value;
Monitor.Pulse(_objLock);
}
}
}
}

I am still having the same issue and have been able to reproduce the
issue without having WCF in the equation. Here is some new code that
produces the same result:

private bool createTeam(string teamName)
{
WaitingValue<bool?> waiting = new WaitingValue<bool?>();

haveAParty();

return waiting.Value.GetValueOrDefault();
}

private void haveAParty()
{
Thread test = new Thread(new ThreadStart(()=>
{
int i = 0;
}));

test.Start();
}

Thanks
 
O

Omatase

Peter said:
Peter Duniho wrote:
[...]
It will take a little more code (unless you write a helper to
encapsulate it),
As an example of such a helper class: [...]
Sorry, at the last minute I decided, unwisely, to make the type a
struct.  The code I posted won't work as written, because you can't have
field initializers in a struct.  Just change "struct" back to "class"
and it should be fine.
The code could be contorted to allow the type to be a struct, but IMHO
it's probably not worth the trouble.

Thanks for your help so far. I have implemented your suggestions using
the helper class as you showed. I did however have to modify a few
things to get it to compile. It looks like this now:

public class WaitingValue<T>
    {
        private T _t;
        private readonly object _objLock = new object();

        public T Value
        {
            get
            {
                lock (_objLock)
                {
                    while (_t == null)
                    {
                        Monitor.Wait(_objLock);
                    }
                }
                return (T)_t;
            }

            set
            {
                lock (_objLock)
                {
                    _t = value;
                    Monitor.Pulse(_objLock);
                }
            }
        }
    }

I am still having the same issue and have been able to reproduce the
issue without having WCF in the equation. Here is some new code that
produces the same result:

private bool createTeam(string teamName)
        {
            WaitingValue<bool?> waiting = new WaitingValue<bool?>();

            haveAParty();

            return waiting.Value.GetValueOrDefault();
        }

        private void haveAParty()
        {
            Thread test = new Thread(new ThreadStart(()=>
                {
                    int i = 0;
                }));

            test.Start();
        }

Thanks

haha oops, That doesn't work for obvious reasons.

please disregard :)
 
P

Peter Duniho

Omatase said:
Peter said:
Peter Duniho wrote:
[...]
It will take a little more code (unless you write a helper to
encapsulate it),
As an example of such a helper class: [...]
Sorry, at the last minute I decided, unwisely, to make the type a
struct. The code I posted won't work as written, because you can't have
field initializers in a struct. Just change "struct" back to "class"
and it should be fine.

The code could be contorted to allow the type to be a struct, but IMHO
it's probably not worth the trouble.

Pete

Thanks for your help so far. I have implemented your suggestions using
the helper class as you showed. I did however have to modify a few
things to get it to compile.

Yeah, sorry about that. Hard to get things perfectly when writing code
without the benefit of the compiler to remind you of silly mistakes,
especially when rushing.

The only comment I have is with respect to your hoisting of the
Nullable<T> aspect out of the class. There's an unfortunate limitation
in C# going on here. In particular, you have two choices:

– allow any type for T, but then find that the class does not work
properly for value types other than Nullable<T>

– require only value types, using Nullable<T> inside the
WaitingValue<T> class, but then not be able to to use reference types
with the class

The problem with the latter is obvious. The class would be just as
useful for reference types as for value types. But IMHO the problem
with the former is much more serious, because no compiler error happens.
Non-nullable value types simply fail to synchronize, returning
uninitialized values.

IMHO, the correct fix is to not use Nullable<T> at all, either in the
client (except when the _client_ needs it) nor in the WaitingValue
class. Here's an implementation that I like much better:

class WaitingValue<T>
{
private T _t;
private bool _fSet = false;
private readonly object _objLock = new object();

public T Value
{
get
{
lock (_objLock)
{
while (!_fSet)
{
Monitor.Wait(_objLock);
}
}

return _t;
}

set
{
lock (_objLock)
{
_t = value;
_fSet = true;
Monitor.Pulse(_objLock);
}
}
}
}

Sorry for the previous off-the-cuff version. I probably should've spent
a little more time thinking about it before posting that code.
[...] I am still having the same issue and have been able to reproduce the
issue without having WCF in the equation. Here is some new code that
produces the same result:

private bool createTeam(string teamName)
{
WaitingValue<bool?> waiting = new WaitingValue<bool?>();

haveAParty();

return waiting.Value.GetValueOrDefault();
}

private void haveAParty()
{
Thread test = new Thread(new ThreadStart(()=>
{
int i = 0;
}));

test.Start();
}

First, that's not a concise-but-complete code example. Second, there's
nothing in that code that ever tries to set the Value property of your
"waiting" variable. So, in that particular example, the reason it never
continues is obvious.

Here's a code example using the WaitingValue implementation I provide
above that works fine:

private bool Test()
{
WaitingValue<bool> waiting = new WaitingValue<bool>();

new Thread(delegate()
{
waiting.Value = true;
}).Start();

return waiting.Value;
}

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