Archived

This forum has been archived. Please start a new discussion on GitHub.

checkedCast() through Ice::Dispatcher

I'm playing with a simple Qt GUI which uses AMI and the new Dispatcher facility. The code follows the examples from the Manual and the MFC demo.

I came across a hang condition and I'm not entirely sure about the cause.

Calling synchronous and asynchronous methods generated from my Slice file work as expected.

But if I have a MyPrx::checkedCast() before making a synchronous call it seems to hang some place between MyDispatcher::dispatch() and arriving into the Qt thread.

If I don't install my Dispatcher, a checkedCast() does not hang.

I noticed that the MFC demo uses uncheckedCast() in the begin_* and end_* AMI calls which makes sense. But shouldn't it be safe to call any remote method through the Dispatcher, including checkedCast()? Or is it special in some way?

If it's supposed to work, I'll do more checking and come up with some sample code.

Thanks a lot,
Alex


Linux, Ice 3.4.0, Qt 4.5.3

Comments

  • benoit
    benoit Rennes, France
    Hi,

    The checkedCast call is not different from any other regular 2-way synchronous call.

    One likely reason for the hang is that there are no more threads available to read the response. It can either be no more threads in the client thread pool (if for example checkedCast is invoked from an AMI callback), or more likely if your dispatcher forwards the dispatch calls to the Qt event loop, the Qt event loop thread can't dispatch the response because it's busy (possibly waiting for the two-way call to return!).

    You must make sure that events dispatched from the Qt thread are always non-blocking (and therefore you shouldn't be making regular 2-way synchronous calls from the event loop thread, only asynchronous calls).

    Cheers,
    Benoit.
  • Thanks Benoit,
    I've gone back and reread the sections on twoway calls, thread pools, bidirectional connection and Bernard's articles on distributed deadlocks.

    I think your second theory is correct:
    I'm making a synchronous call from the Qt thread, I can see a dispatch generated by Ice runtime, it's posted as a Qt even but it's never processed by Qt because it's blocked by the synchronous call.

    I don't quite understand what exactly is being dispatched though.
    My understanding is that 2 kinds of dispatches exist:
    - the incoming remote calls (through the server thread pool), and
    - the results of AMI calls (through the client thread pool).

    In this case I'm not making an AMI call and I'm not expecting an external call (unless checkedCast() leads to some kind of external call).

    The confusing thing is that once checkedCast() is called successfully (by calling it*before* my dispatcher starts dispatching to the Qt thread) I can make a twoway synchronous call getData() without a deadlock. The 3 different cases are listed below.

    A. DEADLOCK
    - setup MyDispatcher to forward to Qt thread
    - from Qt thread : prx=checkedCast() ==> DEADLOCK

    B. DEADLOCK
    - setup MyDispatcher to forward to Qt thread
    - from Qt thread : prx=uncheckedCast(); data=prx->getData() ==> DEADLOCK

    C. OK
    - prx=checkedCast()
    - setup MyDispatcher to forward to Qt thread
    - from Qt thread : data=prx->getData() ==> OK

    It would be great if you can point me to some reading on what exactly happens when I call checkedCast() or uncheckedPrx->getData().

    Thank for your help,
    Alex
  • benoit
    benoit Rennes, France
    Hi Alex,

    There is nothing specific for the checkedCast call, you can consider it like a regular twoway synchronous call (it's just a wrapper for calling ice_isA and casting the proxy type to the right type if the ice_isA is successful).

    In the Ice Dispatcher context, a dispatch can be the following:
    • The notification that a connection establishment succeeded or failed, this in turns notifies the threads waiting on synchronous 2-way calls for the connection establishment (or calls AMI callbacks)
    • A servant dispatch.
    • The response or failure of an AMI call.

    Most likely, C is deadlocking because the connection isn't established before your dispatcher is setup (whereas for A and B it is established). Therefore, since the notification for the connection establishment can't be dispatched (your Qt thread is busy waiting on the synchronous call), you end up with a deadlock. So you should make sure to never make blocking calls from the Qt thread.

    Cheers,
    Benoit.
  • Hi Benoit,

    a short question related to the earlier thread.

    Is there an AMI method which all Ice objects respond to?
    Similar to ice_ping() or ice_isA()

    Thanks,
    Alex
  • benoit
    benoit Rennes, France
    Hi Alex,

    Yes, since Ice 3.4.0, you can use one of the begin_ice_ping() overloads, the AMI version of ice_ping().

    Cheers,
    Benoit.
  • Thanks Benoit,

    begin_ice_ping() does what I need.

    (By the way, I was surprised that I haven't seen any reference to this so I searched the manual. begin_ice_ping() seems to be only mentioned in the C# chapter.)

    Alex
  • matthew
    matthew NL, Canada
    All Ice objects support a set of methods (ice_ping, ice_isA, ice_ids, ice_id). How these are bound to the proxy is defined by the particular language mapping. In C++ therefore you'd expect to find ice_ping and the various AMI combinations o f ice_ping.
  • Thanks Matthew,

    It makes sense now. I guess I tend to think of ice_ping() and friends as somehow special. Part of the mystery is that I can't look up begin_ice_ping() as easily as e.g. begin_getData() corresponding to one of my own interfaces.

    So maybe it would be useful to add a line to the manual saying exactly what you wrote: that all "standard" Ice Object methods have a complete set of AMI equivalents.

    Cheers,
    Alex