Archived

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

Question about AMD (C++)

Hi all!

As far as the AMI part is concerned, now everything of my project is working properly.

As you surely have noticed, I'm a newbie, and I've often found often some difficulties at the beginning when programming with ICE, doubts solved thanks to you (Mark, Benoit and Michi) and your colleagues.

Now I want to add an AMD part, and I've already read all the posts that deal with it (and the AMD part in the manual).

I need my server to serve multiple clients in the case they need to operate with long-running or blocking operations: for this simple example, just for learning purposes, the client run a sendQuery_async (through the AMI) and I want the server to send the response with the AMD.

I have not very clear what should be the implementation of the callback with the AMD in this simple example where I use a single function.
Is this class a sort of the AMI callback class, mirrored in the server?

Shall I leave the implementation of the AMI part or should I modify it?


Can they coexist with such a simple operation?



Thank in advance


Cheers


Alberto

Comments

  • matthew
    matthew NL, Canada
    The use of AMD on the server side and AMI on the client are not dependent upon each other. If you need further assistance you need to ask more concrete questions on exactly what problem you are encountering.
  • Hi matthew, I beg your pardon.


    This is my current Slice interface:
    interface AMISql {
           ["ami"] string sendQuery(string query);
           idempotent void shutdown();
    };
    


    And this is the implementation of the AMI callback:
    class AMI_AMISql_sendQueryI : public Demo::AMI_AMISql_sendQuery
    {
    public:
    	virtual void ice_response(const std::string& result)
      {
    	  cout << endl << "Query result:" << result << endl <<endl;
      }
    
      virtual void ice_exception(const Ice::Exception& ex)
      {
        try {
          ex.ice_throw();
        }
        catch(const Ice::LocalException& e) {
          cout << "sendQuery failed: " << e << endl;
        }
      }
    };
    

    The intention is to make the server able to serve multiple clients in the case they need to operate with long-running or blocking operations: for this simple example, just for learning purposes, the client run a sendQuery_async (through the AMI) and I want the server to send the response with the AMD.

    Now I have this:
    interface SqlQuery {
           ["ami","amd"] string sendQuery(string query);
           idempotent void shutdown();
    };
    



    Shall I leave the previous implementation of the AMI part (in the Client.cpp)?
    What kind of implementation should I add in the server side?


    Thank you in advance


    Regards


    Alberto
  • Do I need a sort of job threads?

    At the moment I do not need the mutuex in this project, even in the future I foresee this feature.


    Cheers


    Alberto
  • matthew
    matthew NL, Canada
    albertods wrote:
    The intention is to make the server able to serve multiple clients in the case they need to operate with long-running or blocking operations: for this simple example, just for learning purposes, the client run a sendQuery_async (through the AMI) and I want the server to send the response with the AMD.

    Now I have this:
    interface SqlQuery {
           ["ami","amd"] string sendQuery(string query);
           idempotent void shutdown();
    };
    

    Shall I leave the previous implementation of the AMI part (in the Client.cpp)?
    What kind of implementation should I add in the server side?

    Thank you in advance

    As I said whether or not the client uses AMI is irrelevant from a server side point of view. The server cannot tell whether the server uses AMI or not -- an AMI call looks just like a synchronous call. On the server side you need to implement sendQuery_async -- if you cannot work out what the signature of this method should be then take a look at the generated code. What problem do you have precisely? Did you read the article "asynchronous programming" in our Connections newsletter (see http://www.zeroc.com/newsletter for more details).
    Do I need a sort of job threads?

    At the moment I do not need the mutuex in this project, even in the future I foresee this feature.

    I don't know whether you need worker threads or not. If you do, however, then I doubt whether you really need to use AMD because I don't see a benefit of introducing your own custom work queue when a perfectly serviceable one exists in Ice in the form of the thread pool.

    Whether or not you need a mutex I also cannot say. You need mutexes if you need to protect your application data against concurrent access. Bu default a server only has one thread in the server side thread pool so it means that this cannot occur. However, this also means that your server cannot have any concurrency which depending on your application may not be a good thing.

    For more information on developing concurrent applications I suggest you read a good book on multi-threaded programming such as Doug Lea's "concurrent programming with Java" or "Programming with POSIX Threads" by Dave
    Butenhof.
  • As I said whether or not the client uses AMI is irrelevant from a server side point of view. The server cannot tell whether the server uses AMI or not -- an AMI call looks just like a synchronous call. On the server side you need to implement sendQuery_async -- if you cannot work out what the signature of this method should be then take a look at the generated code. What problem do you have precisely? Did you read the article "asynchronous programming" in our Connections newsletter (see http://www.zeroc.com/newsletter for more details).


    Thank you Matthew for your reply, and especially for your suggestion as far as concurrent programming is concerned: I appreciated it a lot.


    I know well that AMI and AMD are independent from each other, but the problem here is that I do not know how I can implement the signature of the AMD class.
    I've already read several times the Chat example presented in the 4th Issue of your newsletter, but due to the fact that I'm quite hard minded, it represents for me an argument pretty hard to be dealt with if I consider those two asynchronous facilities taken together for a single method (which is the sendQuery()).


    In the AMI "only" version of the project I have, in the file AMISqlI.cpp, this signature:
    std::string
    AMISqlI::sendQuery(const std::string& s, const Ice::Current&) 
    {
      ...
    }
    
    and in the AMI callback there is the code wrote in the last post.

    In the Server.cpp I instantiate a new Ice object
    Ice::ObjectPtr object = new AMISqlI;
    


    This is the original slice definition:
    module Demo
    {
       interface AMISql {
           ["ami"] string sendQuery(string query);
           idempotent void shutdown(); 
      };
    };
    



    The AMI version of the project works properly, and now I want to add the AMD functionality.

    If I only add the "amd" tag in the slice definition I get this error:
    error C2259: 'AMISqlI' : cannot instantiate abstract class
    due to following members:
    'void Demo::AMISql::sendQuery_async(const Demo::AMD_AMISql_sendQueryPtr &,const std::string &,const Ice::Current &)' : is abstract
    c:\documents and settings\alberto\documenti\visual studio 2005\projects\amisql\amisql_server\amisql.h(252) : see declaration of 'Demo::AMISql::sendQuery_async'



    So I deduce that a signature of the function AMD_AMISql_sendQuery_async [/]was missing, so I added this function in the file AMISqlI.cpp:
    void AMISqlI::sendQuery_async(const Demo::AMD_AMISql_sendQueryPtr& _cb, const std::string& s, const Ice::Current& c)
    {
       ...//the same code as the "normal" sendQuery... is that right?
    }
    




    What direction should I take?
    I want the response of the server not tied to the return of the operation.


    Thank you in advance


    Alberto
  • mes
    mes California
    albertods wrote:
    I want the response of the server not tied to the return of the operation.
    In an AMD operation, the response is not sent to the client until the server sends it explicitly by invoking the callback object provided as the first argument to the operation. If you want your query to be handled by a separate thread, your implementation of sendQuery_async should create the thread and provide the callback object along with the operation parameters. The thread can then invoke cb->ice_response("query results") or cb->ice_exception() when necessary. Note that the Ice run time does not require sendQuery_async to respond to the request before the function returns.

    Section 31.4 in the Ice manual provides an example of using AMD.

    Hope that helps,
    - Mark
  • Thanks Mes.

    I have written a simple example that uses both AMD and AMI, starting from the Printer's code.


    I still get this compilation error (the same error I'm used to receive...), and I think I'm driving crazy :)
    \Server.cpp(99) : error C2259: 'PrinterI' : cannot instantiate abstract class
            due to following members:
            'void Demo::Printer::printString_async(const Demo::AMD_Printer_printStringPtr &,const std::string &,const Ice::Current &)' : is abstract
            c:\Ice-3.1.0\demo\book\printer\Printer.h(255) : see declaration of 'Demo::Printer::printString_async'
    



    What might be the cause?



    Thanks in advance


    Alberto
  • marc
    marc Florida
    Change "const ::std::string" to "const ::std::string&" in your code. Strings are passed by C++ const reference (regardless of whether you use AMD or not).
  • Thank you very much! And excuse me if sometimes I might post silly questions :p
  • File .dll not found

    I get an error message, after launching the server, that says:
    "it's impossibile to run the application. File ice31d.dll not found".


    What could be the cause of this message?

    I could not find the ice31d.dll anywhere...


    Thanks



    Alberto
  • "ice31d.dll" is the "debug" version of the Ice DLL. This means that it was built debugging information turned on and debug version of the Microsoft runtime library.

    The library location depends on how you installed Ice. Generally speaking it is in the Ice "bin" directory. For example:

    c:\Ice-3.1.0\bin\ice31d.dll

    "ice31d.dll" is already built for you in the Windows installer. If you are using the source distribution, you need to build Ice with the active configuration set to "Debug".

    Cheers
  • Thanks a lot Beagles.


    Now I have this issue:
    executeQuery failed: .\ConnectionI.cpp:272: Ice::CommunicatorDestroyedException: communicator object destroyed
    

    I followed the chapter 31.4 of the manual, but I'm pretty sure there is something missing in the code.

    Is there anything wrong in the code?
    How can I manage the response thread?


    Step by step I'm getting more and more used to the AMI/AMD :)


    Thanks in advance


    Alberto
  • mes
    mes California
    Your client is destroying the communicator before the response is received. You should either change your client to make a synchronous request instead, or your client must wait for the AMI request to complete before destroying the communicator.

    - Mark
  • Thanks a lot Mes.



    The "printString_async" records the callback requests and arguments in a Job that is added to this queue:
    IceUtil::Mutex::Lock sync(*this);
    JobPtr job=new Job(...);
    _jobs.push_back(job);
    
    ...as it's written in the manual.

    How can I manage the response thread?

    Has the function "printString_async" the role to empty the thread's queue as well, or this task must be performed by the main function of the server?



    Regards


    Alberto
  • mes
    mes California
    An application would typically use one or more worker threads to remove jobs from the queue and execute them. For an example, see demo/IceUtil/workqueue.

    Please note that answering questions about application design is outside the scope of the free support we provide on this forum. If you need further assistance, contact us at info@zeroc.com to inquire about consulting services.

    Take care,
    -Mark