Archived

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

How to solve this ...

2»

Comments

  • benoit
    benoit Rennes, France
    Right, the work queue is using a std::list to store the work items so add() and nextItem() need to be synchronized to modify the list.

    Implementing another data structure to do what you want is perhaps possible but I don't think it's worth the effort. It's certainly not trivial to implement and in any case I don't think you'll notice any performance improvements.

    Your application will spend most of the time executing the work items (without holding the work queue lock). Compared to this, the cost of add() and nextItem() won't be significant.

    Cheers,
    Benoit.
  • :eek: If the mutexes wont cost much, maybe I will just lock the whole list...:p
    Thank you~
  • hi, I'm still wondering how to load a class from an DLL file to the ICE run time.
    I will load an factory from an DLL file.
    I can get the instance of the class from the factory.
    The class is defined in a separate Slice definition.
    The file generated by slice2cpp the slice definition was compiled into the DLL file.
    The servant for the class is also compiled into the DLL file.

    In the server or client ICE run time, what & how should I do to let ICE run time could transfer the class loading from the DLL file ? Some codes would be better.

    Thank you~~~
  • matthew
    matthew NL, Canada
    For an example of how to do this take a look at the IceBox server implementation. It loads an IceBox service dynamically from a DLL at runtime. You can look at the icebox demo to see how to implement the dynamically loaded class.
  • I've read some codes of IceBox, but it only load service codes from dll. What I want to do is load classes from dll and then I can transfer it's instances between server and clients.
    I know how to load classes form dll and how to use it. But don't know what should I do to let the classes could be used by the ICE runtime, especially could be transfer on the net.
    :confused:
  • matthew
    matthew NL, Canada
    I'm not sure really what you want to do. You can load whatever you like from the DLL. What exactly do you want to do? Please give a specific example and we can show how to solve it (assuming its possible).
  • Sorry~
    An example :
    It is a MMORPG and the Server and Clients will communicate by sending & receiving message objects (as the Command pattern). I'd like the message classes to be load from dlls so that I can add new message classes easily. But the instances of these message classes must be transfer on the network and that means the Ice runtime must know something to make an local object from the network data. So after I loading the dll and being able to get instances of the classes, what should I do ?
    And what I want to do is NOT just loading the servant classes BUT the servant class and the base class compiled from the slice definition.
    Is that more clear ? :rolleyes:
  • marc
    marc Florida
    This is out of the scope of what Ice can do for you. In other words, you have to implement your own mechanism to load appropriate DLLs. You could transfer DLLs using Ice as an octet sequence, but how to install them and activate them would be up to your code.
  • :(
    So I ask in this way :
    I have a shared object file "msg.so".
    And in the Server and the clients there're codes like below:
    hl= load("msg.so");
    factory_function= (FACTORY_FUNCTION)get_function(hl, "factory_function");
    MessagePtr msg= factory_function("MessageAttack");
    
    Now I have a derived class from class Message and class Message is a class compiled from slice definition.
    What should I do next to let Ice could transfer "msg" on the network?
    :confused:
    Thank you~
  • matthew
    matthew NL, Canada
    There is nothing special about a shared library. I don't understand what your confusion is. I can only answer that you have to define the datatype in slice, and then send it via a remote procedure call.
    // Slice
    class Message
    {
      // some data members.
    };
    
    interface Foo
    {
      void someMethod(Message m);
    };
    
    // C++
    MessagePtr msg = ...;
    FooPrx foo = ...;
    foo->someMethod(msg);
    
  • :eek: Don't need any registering ? When the object data arrives at the other side of the network, would it be rebuilt into the instance of the right class ?:eek:
  • matthew
    matthew NL, Canada
    If the receiver of the class does not understand the full structure it will slice the class. That is cut off all the pieces it does not understand. For example, if you have
    class a
    {
     int i1;
    };
    
    class b extends a
    {
     int i2;
     int i3;
    };
    
    interface f
    {
      void do(a an_a);
    };
    

    If you pass to f::do an instance of b and the receiver does not know the class b it will be sliced by the receiver to simple an instance of class a. You can find more information of this in section 4.11 of the Ice manual. If you want to see some tracing information on slicing then set the property Ice.Trace.Slicing to 1.

    I suspect you are passing abstract classes around. Something like this:
    class Command
    {
      void dosomething();
    };
    

    Then you have somewhere:
    class EatCommand extends Command
    {
      Food food;
    };
    

    And you want to pass an instance of this command to a server that previously knows nothing about the class. In this case you will get a NoObjectFactoryException since the class cannot instantiate the EatCommand class.

    I think really what you want to do is register a default object factory. Here you will get calls to instantiate any objects that get sent to your server. So from that you can map the type id to a shared library. Then load the shared library, and instantiate the class, and do whatever you want to do.
  • That's it~
    matthew wrote:

    I think really what you want to do is register a default object factory. Here you will get calls to instantiate any objects that get sent to your server. So from that you can map the type id to a shared library.
    Then load the shared library, and instantiate the class, and do whatever you want to do.
    But how to do this ? Which APIs should I use ? :)
  • matthew
    matthew NL, Canada
    Look at 6.14.5 of the Ice manual.
  • matthew wrote:
    Look at 6.14.5 of the Ice manual.

    In 6.14.5 there was written this :
    6.14.5 wrote:
    Given a factory implementation, such as our ObjectFactory, we must
    inform the Ice run time of the existence of the factory:
    Ice::CommunicatorPtr ic = ...;
    ic->addObjectFactory(new ObjectFactory, "::M::TimeOfDay");
    Now, whenever the Ice run time needs to instantiate a class with the type ID
    "::M::TimeOfDay", it calls the create method of the registered
    ObjectFactory instance.

    In this example there was only one class in the factory. So if there was many classes in one factory, what kind of ID should I give for the factory ?


    If I write a slice difinition which has a class "AttackMessage" and compiled it into files "AttackMessage.h" and "AttackMessage.cpp". Then I write an implementation class AttackMessageI in files "AttackMessageI.h" and "AttackMessageI.cpp". And there is also a factory in them too.
    Then I complie the 4 files into a dll.
    Then I load the dll and register the factory into the Ice Communicator.
    Can I send & receive the instance of class AttackMessageI now ?

    Thank you~
  • matthew
    matthew NL, Canada
    sjinny wrote:
    In this example there was only one class in the factory. So if there was many classes in one factory, what kind of ID should I give for the factory ?

    If you use "" as the registered object-id you set the default object factory which is called if no object factory for the given type is available.
    sjinny wrote:
    If I write a slice difinition which has a class "AttackMessage" and compiled it into files "AttackMessage.h" and "AttackMessage.cpp". Then I write an implementation class AttackMessageI in files "AttackMessageI.h" and "AttackMessageI.cpp". And there is also a factory in them too.
    Then I complie the 4 files into a dll.
    Then I load the dll and register the factory into the Ice Communicator.
    Can I send & receive the instance of class AttackMessageI now ?
    Thank you~

    You send the instance of AttackMessage, not the implementation. The receiver of this message must also be able to instantiate an implementation of the AttackMessage class also (assuming that this class is abstract -- ie: has a method definition).
  • matthew wrote:
    If you use "" as the registered object-id you set the default object factory which is called if no object factory for the given type is available.
    Can I register more than one default factory ?
    matthew wrote:
    You send the instance of AttackMessage, not the implementation. The receiver of this message must also be able to instantiate an implementation of the AttackMessage class also (assuming that this class is abstract -- ie: has a method definition).
    So if the server and the clients both do all the steps to loading the dll, would it be just all right to send & receive objects between them ?

    :)
  • sjinny wrote:
    Can I register more than one default factory ?
    No. Only one default factory can be registered per communicator.

    You can also register the same factory multiple times, each time for a different type ID. That effectively gives you what you would otherwise do with multiple default factories.
    So if the server and the clients both do all the steps to loading the dll, would it be just all right to send & receive objects between them ?

    Yes, no problem with that.

    Cheers,

    Michi.
  • michi wrote:
    No. Only one default factory can be registered per communicator.

    You can also register the same factory multiple times, each time for a different type ID. That effectively gives you what you would otherwise do with multiple default factories.

    If there are many classes in one factory, this factory would be registered many times ...
    Are there any other solutions ?

    Thank you~
  • matthew
    matthew NL, Canada
    Register a default locator and have it do all of the work. This is what I would recommend for your use-case.
  • Like our discussion before, I write a little codes to implement the design. But I meet exceptions both in the server and the client:
    In the Server:
    mmo.exe: warning: dispatch exception: unknown c++ exception
    identity: Scene
    facet:
    operation: sendMsg
    
    In the client:
    mmo.exe: .\Outgoing.cpp:418: Ice::UnknownException:
    unknown exception:
    unknown c++ exception
    
    About the RPC method sendMsg, I find that the client's exception is coming out after the server's exception.
    Ice's src file "incoming.cpp": (BK stands for "break point")
    void
    IceInternal::Incoming::invoke(const ServantManagerPtr& servantManager)
    {
    ......
        try
        {
    	try
    	{
    	    if(servantManager)
    	    {
    		_servant = servantManager->findServant(_current.id, _current.facet);
    		if(!_servant)
    		{
    		    _locator = servantManager->findServantLocator(_current.id.category);
    		    if(!_locator && !_current.id.category.empty())
    		    {
    			_locator = servantManager->findServantLocator("");
    		    }
    		    if(_locator)
    		    {
    			_servant = _locator->locate(_current, _cookie);
    		    }
    		}
    	    }
    	    if(!_servant)
    	    {
    		if(servantManager && servantManager->hasServant(_current.id))
    		{
    		    status = DispatchFacetNotExist;
    		}
    		else
    		{
    		    status = DispatchObjectNotExist;
    		}
    	    }
    	    else
    	    {
    [COLOR="Red"]BK1[/COLOR]		status = _servant->__dispatch(*this, _current);
    	    }
    	}
    	catch(...)
    	{
    [COLOR="Red"]BK2[/COLOR]	    if(_locator && _servant && status != DispatchAsync)
    	    {
    		_locator->finished(_current, _servant, _cookie);
    	    }
    
    	    throw;
    	}
    ......
    }
    
    My src file "factory.cpp"
    ObjectPtr Factory::create( const std::string& __type )
    {
    [COLOR="Red"]BK3[/COLOR]    return static_cast<Object*>( newInstance( __type ) );
    }
    
    Ice's src file "handle.h"
    template<typename T>
    class Handle : public ::IceUtil::HandleBase<T>
    {
    public:
        
        Handle(T* p = 0)
        {
    	this->_ptr = p;
    
    	if(this->_ptr)
    	{
    [COLOR="Red"]BK4[/COLOR]	    incRef(this->_ptr);
    	}
        }
    ...
    
    And in the server, I find that the exception is coming out after these steps:
    reach 2 twice to BK1. And in the 2nd time:
    reach to BK3. The new instance is created correctly. And before the function returns:
    reach to BK4 to construct a temp Ptr obj for returning. BUT when the code "incRef(this->_ptr);" runs, it throw an exception and:
    reach to BK2.
    And it seems that the code "incRef(this->_ptr);" didn't call the function "__incRef()" in the Ice's src file "GCShared.cpp":
    void
    IceInternal::GCShared::__incRef()
    {
        gcRecMutex._m->lock();
        assert(_ref >= 0);
        ++_ref;
        gcRecMutex._m->unlock();
    }
    

    For several days I can't find out what exact bug causes the exception and I can't go on with the project.
    Could anybody help me? If you have time...
    Thanks~

    And here is info about the project.
    I create two VC++ projects:
    1st, the mmolib project. It's output is a dll file named "mmolib.dll".
    2nd, the mmo project. It's output is a .exe file named "mmo.exe". It links with mmolib.
    And I also create a test project: TestScene. It's output is a dll file named "TestScene.dll". It also links with mmolib. And I write two config files, one for the server and one for the client:
    ice_config_server.cfg
    MMO.EntryFileName = TestScened.dll
    MMO.EntrySceneClassName = ServerScene
    MMO.AdapterName = World
    MMO.AdapterEndpoints = tcp -p 50000
    
    ice_config_client.cfg
    MMO.EntryFileName = TestScened.dll
    MMO.EntrySceneClassName = ClientScene
    MMO.AdapterName = World
    MMO.AdapterEndpoints = tcp -p 50001
    
    The running steps are described as below:
    1.In a console run command "mmo.exe --Ice.Config=ice_config_server.cfg"
    1.1The mmo.exe load the file TestScened.dll and get an instance of class ServerScene in the dll.
    1.2The mmo.exe has a method breathe:
    template < typename Precision >
    void World<Precision>::breathe()
    {
        _scene->breathe();
    }
    
    So the method breathe() of the ServerScene will keep running.
    2.In another console run command "mmo.exe --Ice.Config=ice_config_client.cfg"
    2.1The mmo.exe load the same dll file but get the instance of another class ClientScene in the dll.
    2.2In the method init() of the ClientScene, the client send an instance of class MsgLogon to the server through an RPC. And in this RPC the exception occurs. After the exception the server is still running but the client stops.

    The slice definitions are here:
    mmo.ice: (compiled into the mmolib)
    #ifndef MMO_ICE
    #define MMO_ICE
    
    module MMO
    {
    
    interface SceneIce;
    interface ObjectIce;
    
    class MessageIce
    {
    	bool preProcess( ObjectIce actor, SceneIce scene );//return true to be added into the queue of the scene. Don't abuse this method!
    	bool exec( SceneIce scene );
    };
    
    interface ObjectIce
    {
    	void sendMsg( MessageIce msg );
    };
    
    interface SceneIce extends ObjectIce
    {
    };
    
    };
    
    #endif
    
    testscene.ice: (compiled into the TestScene)
    #ifndef TESTSCENE_H
    #define TestScene_H
    
    #include "mmo.ice"
    
    module TestScene
    {
    
    class MsgLogonIce extends MMO::MessageIce
    {
    	string userID;
    	string passwd;
    	MMO::SceneIce* client;
    };
    
    };
    
    #endif
    

    :confused::confused::confused::confused::confused::confused::confused:
  • marc
    marc Florida
    I'm afraid the only information we can provide here is that your server implementation (not the Ice core) raises an exception (not an Ice exception), which is then transferred to the client as an UnknownException.

    If you would like us to provide you with consulting services to debug this problem, please contact us at sales@zeroc.com.