Thread overview
Multi-Thread Application problem
Feb 04, 2008
Benjamin Schulte
Feb 04, 2008
Benjamin Schulte
February 04, 2008
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*
February 04, 2008
"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


February 04, 2008
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;
};

February 04, 2008
"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