Archived

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

Thread problem

I want to create several threads in a server adapter's method,slice file is:
module transfer {

	class Target {
		int id;
		string ip;
	};
	
	sequence<Target> Des;
	
	sequence<byte> Frame;
	
	
	
	interface Service {
		["ami"] void transfer(Des targets,int len,Frame f);
	};
};

in transfer method, I write:
vector<IceUtil::ThreadControl> threads;
	for (;;)
	{
		string token;
		getline(ss, token, '|');
		if( ss.fail()) 
			break;
		IceUtil::ThreadPtr thread1=new TransferThread(token,const_cast<transfer::Frame&>(f));
		threads.push_back(thread1->start());
	}
	// Wait for all threads to finish
	for (vector<IceUtil::ThreadControl>::iterator i
		= threads.begin(); i != threads.end(); ++i) {
			i->join();
	}
I just split a string with '|', and for each of them, I create a thread ,start it, wait until them done.

In thread's run method:
void TransferThread::run(){
	try { 
		int argc = 0;
		Ice::InitializationData initData;
		initData.properties = Ice::createProperties();
		initData.properties->load("config");
		Ice::CommunicatorPtr ic = Ice::initialize(argc, 0, initData);
		Ice::ObjectPrx base = ic->stringToProxy(location);
		base=base->ice_datagram();
		ServicePrx adaptor = ServicePrx::uncheckedCast(base);
		if (!adaptor)
			throw "Invalid proxy";
		//there is nothing to use
		TargetPtr t=new Target();
		t->id=1;
		t->ip="127.0.0.1";
		vector<TargetPtr> d;
		d.push_back(t);
		AMI_Service_transferPtr handle=new AMI_Service_transferI;
		adaptor->transfer_async(handle,d,frame.size(),frame);
	} catch (const Ice::Exception& ex) { 
		cerr << ex << endl;
	} catch (const char* msg) {
		cerr << msg << endl; 
	} 
}
I use AMI so I think the thread will return at once, not blocking the transfer method to return.

But, I got some Thread exited with code 3... and sometimes I got the system resource limit error.
Is there something wrong I do? I feel that some threads dead, but I didnt close them....

Comments

  • benoit
    benoit Rennes, France
    Hi,

    Your thread run() method doesn't destroy the communicator. This is causing some resources to not properly be released and most likely the resource limit errors you're observing.

    Why do you start a new thread that creates a brand new communicator for each AMI request? Why not simply invoke transfer_async directly, such as:
    // C++
    ServicePrx adaptor = ...
    for (;;)
    {
    	string token;
    	getline(ss, token, '|');
    	if( ss.fail()) 
    		break;
    
    	TargetPtr t=new Target();
    	t->id=1;
    	t->ip="127.0.0.1";
    	vector<TargetPtr> d;
    	d.push_back(t);
    	AMI_Service_transferPtr handle=new AMI_Service_transferI;
    	adaptor->transfer_async(handle, d, frame.size(), frame);
    } 
    

    If you need to keep the separate threads, you should at least consider sharing the communicator between the threads.

    Cheers,
    Benoit.
  • Thanks, now it works!
  • matthew
    matthew NL, Canada
    How did you fix it? With the code as presented, if you "fix" the issue by destroying the communicator your code will sometimes fail in unexpected ways as you never wait for the AMI request to complete (which, btw, defeats the purpose of using AMI in the first place).
  • I use communicator as a var in class ServiceI, and I nerver destory it in transfer method, I destory it in ServiceI's destruction method.
    And I'm not using threads now, I just use AMI to send the request. Codes:
    for (;;)
    	{
    		string token;
    		getline(ss, token, '|');
    		if( ss.fail()) 
    			break;
    		Ice::ObjectPrx base = ic->stringToProxy(token);
    		base=base->ice_datagram();
    		ServicePrx adaptor = ServicePrx::uncheckedCast(base);
    		//there is nothing to use
    		TargetPtr t=new Target();
    		t->id=1;
    		t->ip="127.0.0.1";
    		vector<TargetPtr> d;
    		d.push_back(t);
    		AMI_Service_transferPtr handle=new AMI_Service_transferI;
    		try{
    			adaptor->transfer_async(handle,d,f.size(),f);
    		}catch(Ice::Exception){
    
    		}
    	}
    
    As you said, I have a question about AMI, if the transfer_async method returns immediately, what happens to AMI_Service_transferPtr handle, I see this typedef:
    typedef ::IceUtil::Handle< ::transfer::AMI_Service_transfer> AMI_Service_transferPtr;
    

    I think ::IceUtil::Handle class is something like smart pointer , handle var, it just disappears? Then how can the callback be called? :confused:

    I think maybe I'm using it the wrong way ,can you point me the right way?:o
  • benoit
    benoit Rennes, France
    Hi,

    Yes, the Ptr object is a smart pointer, see here for more information on Ice smart pointers.

    The Ice runtime keeps a smart pointer to the callback object when you call transfer_async to prevent the callback object from being destroyed. Once the Ice runtime calls on the callback, it also gets rid the smart pointer and the callback object endup being destroyed if your code doesn't hold any smart pointers for it.

    Note that the use of AMI for sending datagram requests is of limited use: it's mostly useful if your proxy contains endpoints with DNS names or is an indirect proxy and you want to make sure the call doesn't block. Otherwise, sending datagrams usually doesn't block. You should also be aware that datagrams can be lost and are subject to size limits which might be an issue depending on the kind of data you transfer.

    Cheers,
    Benoit.