www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Multi-Thread Application problem

reply Benjamin Schulte <Aldoric gmx.de> writes:
Hello,

I'm having a problem with a problem in a multi threaded application since
several days.

The problem itself is easy to describe. Let's say theres are two threads.
Thread A and Thread B.
Thread A has to do most of the things for the application - drawing, movement,
etc. (It's a game)
Thread B has to do all the loading stuff. Well since OpenGL doesn't support
handling drawing methods from Thread B there is a class that does simply:
Thread B requests to call something and waits for Thread A to handle it - then
it continues.

But sometimes - without any real sense where it happens Thread A stops - and
Thread B - well, Thread B waits for Thread A at the told position.


However, I now wondered if it's possible that a Thread goes into the "critical
mode" as soon a 'delete' is being called.

like:

delete abc;
-->
~this( )
{
// Within this there is no thread switching??
}
<--
// Now we can switch again


Hope you can understand what I mean >.> *not the best english*
Feb 04 2008
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Benjamin Schulte" wrote
 Hello,

 I'm having a problem with a problem in a multi threaded application since 
 several days.

 The problem itself is easy to describe. Let's say theres are two threads. 
 Thread A and Thread B.
 Thread A has to do most of the things for the application - drawing, 
 movement, etc. (It's a game)
 Thread B has to do all the loading stuff. Well since OpenGL doesn't 
 support handling drawing methods from Thread B there is a class that does 
 simply:
 Thread B requests to call something and waits for Thread A to handle it - 
 then it continues.

 But sometimes - without any real sense where it happens Thread A stops - 
 and Thread B - well, Thread B waits for Thread A at the told position.


 However, I now wondered if it's possible that a Thread goes into the 
 "critical mode" as soon a 'delete' is being called.

 like:

 delete abc;
 -->
 ~this( )
 {
 // Within this there is no thread switching??
 }
 <--
 // Now we can switch again


 Hope you can understand what I mean >.> *not the best english*

This seems to imply that you are doing a wait operation in your destructor? This is a bad idea. Destructors are only for cleaning up system resources. Perhaps you can post your destructor code that you suspect is hanging here and we can have a look. BTW, being in the destructor in itself will not force thread switching to stop, but if the destructor is being called by the garbage collector, all threads are halted while the garbage collector runs. -Steve
Feb 04 2008
parent reply Benjamin Schulte <Aldoric gmx.de> writes:
Hi,

thanks for your reply. I guess this was the fact I didn't know so far. Is it
for the constructor equal?

But yes, I had a sleep in the deconstructor, waiting for the other thread. I
then just wonder why it worked sometimes and only a few times it didn't. But
maybe there's still another bug in my applcation.

But here's the code - maybe there's still a way to optimize it. But I guess
first I need to replace the deconstructor with a free-method deleting itself
after freeing the resources.

ThreadCall.doEvents( ) is being called from Thread A.



class someclass {
~this( )
{
	// Outside-Of-Thread call
	ThreadCall.call( function( uint id ) {

		glDeleteBuffersARB( 1, cast(uint*)&id );
		return 0;

	}, cast(uint)vboBuffer );
}
}





// Alias
alias int function( uint ) ThreadCallPtr;

/*********************************************************************
 * The thread call class
*********************************************************************/
class ThreadCall
{
	/*********************************************************
	 * Call a method
	*********************************************************/
	static uint call( ThreadCallPtr ptr, uint param )
	{
		uint myId = getUniqueId( );

		// If myId is equal to the main thread ID, we don't
		// have to wait until we can call this method
		if( myId == mainThreadId )
		{
			// Call method
			return ptr( param );
		}
		else
		{
			// Well, we have to wait for the main thread

			// Create call
			
			ThreadCall c = new ThreadCall;
			c.method     = ptr;
			c.param      = param;
			
			// Append call to event list
			mainSemaphore.enter( );
			calls ~= c;
			mainSemaphore.leave( );

			// Wait for call to be finished	
			while( !c.finish ) usleep(10);

			// Delete my item and return its result
			int r = c.result;
			delete c;
			
			return r;
		}
	}
	
	/*********************************************************
	 * Do all events (Called in the main thread)
	*********************************************************/
	static void init( )
	{
		// Get main-thread ID
		mainThreadId  = getUniqueId( );
		mainSemaphore = new Semaphore( );
	}
	
	/*********************************************************
	 * Return an unique ID describing the current thread
	 * WARNING: OS DEPENDEND!	 
	*********************************************************/
	static uint getUniqueId( )
	{
		// Windows method
		return cast(uint)GetCurrentThreadId( );	
	}

	/*********************************************************
	 * Do all events (Called in the main thread)
	*********************************************************/
	static void doEvents( )
	{
		mainSemaphore.enter( true );
		
		// Go through every item
		foreach( ThreadCall c; calls )
		{
			// Call method
			c.result = c.method( c.param );
			c.finish = true;
		}

		// Clear list, cause we did all
		calls.length = 0;		
		mainSemaphore.leave( );
	}

	/********************************************************/
	ThreadCallPtr		method;
	uint				param;
	int					result;
	bit					finish = false;
	
	static ThreadCall calls[];
	static uint       mainThreadId;
	static Semaphore  mainSemaphore;
};
Feb 04 2008
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"Benjamin Schulte" wrote
 Hi,

 thanks for your reply. I guess this was the fact I didn't know so far. Is 
 it for the constructor equal?

 But yes, I had a sleep in the deconstructor, waiting for the other thread. 
 I then just wonder why it worked sometimes and only a few times it didn't. 
 But maybe there's still another bug in my applcation.

 But here's the code - maybe there's still a way to optimize it. But I 
 guess first I need to replace the deconstructor with a free-method 
 deleting itself after freeing the resources.

 ThreadCall.doEvents( ) is being called from Thread A.



 class someclass {
 ~this( )
 {
 // Outside-Of-Thread call
 ThreadCall.call( function( uint id ) {

 glDeleteBuffersARB( 1, cast(uint*)&id );
 return 0;

 }, cast(uint)vboBuffer );
 }
 }

What is stopping you from calling glDeleteBuffersARB from the destructor? (I'm assuming glDeleteBuffersARB is a C call). Aside from that, probably the only good way to do this is to queue the call and not wait for the result. However, it is possible that the semaphore is already locked. I remember someone having a problem with freeing resources by using a C function in a destructor, and finding that a lock was held by a suspended thread. I think this problem has been solved in Tango's GC (I could be wrong). You may want to look into that. -Steve
Feb 04 2008