Archived

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

problem of abort() invoked by GC::GC()

I use the ice client side in a COM component that be created/released multiple times by another application. I initial the ice communicator when the COM object creation each time, and destroy and set null the communicator when the COM object release each time.

But the GC is not member of communicator but global variable within ice12.dll scope. we cannot destruct the GC object directly. So since creation of the COM component second time, the abort() is invoked because the _numCollectors > 0, the application is enforced to exit.

But the most surprising is that the second creation of COM component is not always failed. If the ice client side can not connect the server side, the second creation will failed always. But if the ice client side can connect to server side (the checkedCast have not exception and return ok), the second creation is not always failed, maybe the third, fourth, or fifth creation will failed.

how should I do?

Comments

  • I got the reason of this problem. I think it should be a bug of ICE.

    When construct the first communicator, the constructor of CommunicatorI create a new global IceUtil::GC object. But when destroy the last communicator, the CommunicatorI does not release the global GC object. So if create the Communicator again, the GC constructor will invoke the abort() to exit the application.

    another puzzle is why the abort() is not always invoked since second creation of communicator. This is relative with my usage to the communicator. I write the ice client in a OLE-based Property sheet(a COM component), and each property page(OLE property page, also COM component) is ice client too. They (the pages) share the communicator created in property sheet. When the page is deactived, some of pages invoke the destroy() of communicator, another not.

    The CommunicatorI::destroy() have not code to protect from destroying multiple times, so communicatorCount will become the negative number after more than one destroy() invocation. After then, the condition that ++communicatorCount == 1 cannot be true when popup the property sheet and creating the communicator again. then the GC object will not be construct again. so abort() never got invocation in this case. If I only browse the page that do not invoke destroy() or cannot connect to server side (no any page is actived), the abort() will be invoked, the application will exit at once.


    so I have to change the CommunicatorI::destroy() as following, please tell me if it's OK :

    void
    Ice::CommunicatorI::destroy()
    {
    //Paul Ling: Don't destroy again if have been destroyed.
    if (_destroyed)
    return;

    InstancePtr instance;

    {
    RecMutex::Lock sync(*this);

    if(!_destroyed) // Don't destroy twice.
    {
    _destroyed = true;
    instance = _instance;
    }
    }

    bool last;
    {
    IceUtil::StaticMutex::Lock sync(gcMutex);
    last = (--communicatorCount == 0);
    }

    if(last)
    {
    //
    // Wait for the collector thread to stop if this is the last communicator
    // to be destroyed.
    //
    theCollector->stop();
    }

    theCollector->collectGarbage(); // Collect whenever a communicator is destroyed.

    if(last)
    {
    IceUtil::StaticMutex::Lock l(gcMutex);

    if(gcTraceLevel)
    {
    Trace out(gcLogger, gcTraceCat);
    out << "totals: " << gcStats.collected << "/" << gcStats.examined << ", "
    << gcStats.msec << "ms" << ", " << gcStats.runs << " run";
    if(gcStats.runs != 1)
    {
    out << "s";
    }
    }
    gcTraceLevel = 0;
    gcLogger = 0;

    //Paul Ling: remove GC collector if the last communicator is destroyed.
    theCollector = 0;
    }

    if(instance)
    {
    instance->destroy();
    }
    }
  • I recently fixed a race condition in the GC code. The fix is a bit more complex than what you suggest -- it will be included in the next Ice release, of course. Meanwhile, I've attached src/Ice/CommunicatorI.cpp, src/IceUtil/GC.cpp, and include/IceUtil/GC.h. Can you please try with those? I think these should fix your problem.

    Cheers,

    Michi.
  • I think that if some one invoke the Communicator::destroy() multiple times, just like my application, the ++communicatorCount == 1 (in constructor of CommunicatorI) will never be true because the communicatorCount will be subtracted to negative in destroy() that can invoke twice. So the GC collector will never be created again after released at the time of the last communicator destroyed. Is there some problems?

    I think the destroy twice protection is necessary, so the following code should be added at front of the destroy().

    if (_destroyed) return; // protected the communicatorCount become to negative

    Thanks for your reply.
  • Originally posted by paulling
    I think that if some one invoke the Communicator::destroy() multiple times, just like my application, the ++communicatorCount == 1 (in constructor of CommunicatorI) will never be true because the communicatorCount will be subtracted to negative in destroy() that can invoke twice. So the GC collector will never be created again after released at the time of the last communicator destroyed. Is there some problems?

    I think the destroy twice protection is necessary, so the following code should be added at front of the destroy().

    if (_destroyed) return; // protected the communicatorCount become to negative

    Thanks for your reply.

    Hmmm... I guess you are right -- the first few lines of destroy() should be changed to read:
    {
        RecMutex::Lock sync(*this);
        if(_destroyed)
        {
             return;
        }
        else
        {
            _destroyed = true;
            instance = _instance;
        }
    }
    

    Thanks for spotting this!

    Cheers,

    Michi.
  • Thank you. I am very glad to discuss this problem with you. I hope I can dedicate my time to this project.

    I have another question, how can I create multiple servant instances (one for each client)? I think the first servant that client can access cannot have multiple instances. isn't it? Then the first object can create one sub-object for each client?

    It is different with DCOM that will provide different object instance for each client request by default.
  • Originally posted by paulling
    I have another question, how can I create multiple servant instances (one for each client)? I think the first servant that client can access cannot have multiple instances. isn't it? Then the first object can create one sub-object for each client?

    It is different with DCOM that will provide different object instance for each client request by default.

    The usual way to do this is to use the factory pattern:
    interface FooObject {
        // Foo operations here...
        destroy();
    };
    
    interface FooFactory {
        Foo create(/* params */);
    };
    

    Clients create the object by calling create() on the factory. When they no longer need the object, they call destroy() on the object.

    Cheers,

    Michi.