Link to home
Start Free TrialLog in
Avatar of zmau
zmau

asked on

Changing stack size while thread is active.... Is it possible ??

Hello all,
I am writing a DLL (in windows), with a function that needs a lot of stack size.
The problem is that I am not creating the thread.
So is there a way to change the stack size while the thread is running ?
Alternatively, is there a way to "catch" thread creation, and vrify that the stack size is big enough ?


Thanks
zmau
Avatar of Zoppo
Zoppo
Flag of Germany image

Hi zmau,

I don't think there's a way to change the size of a thread's stack in Windows, and the only way I can imagine to 'catch thread creation' is by hooking the CreateThread function from the Win32 API ... that's possible, but in my opinion this feels more like a hack than a solution or workaround.

I'm not sure if I understand the problem correctly - as I understand it, you write your own function, which is called from a thread which is started in a DLL that you can't modify (third-party?), so you don't have any influence on the thread creation - is that right?

If so: could you tell something about the reason why your function needs such a large stack-size?

Maybe there's a way to workaround this issue ... one way I can think of is to change the function running in the DLL's thread to create and start a new thread and to wait until it terminates - for the new thread, to which you can move your functionality, you can specify a stack of any arbitrary size (see CreateThread).

Best regards,

ZOPPO
Avatar of zmau
zmau

ASKER

Thanks a lot,
Your analysis looks correct to me (I was hoping that I was wrong).
It's a C++ DLL, which uses OpenMP   (OpenMP create it's own threads, and this adds to the complication).
The threads are being created by the application which we do not have control over it.
My function is a recursive function, which does not take too much stack size, but the recursion may be large.
The problem is mainly that I do not have control over the application which already uses the stack (and sometimes over use).
I have thought of your solution (creating another thread), but it might not work for the OpenMP threads. One more point is that we have many functions in this DLL, and this solution requires changing them all (but it is still considered).

Thanks again
zmau
No problem ... 'but it might not work for the OpenMP threads' - to be honest I don't have much knowledge about OpenMP, but from my understanding it shouldn't make a big difference.

IMO it should alway be possible to replace something like this pseudo-code:
OpenMPThreadProc(...)
{
    MyRecursiveFunc();
}

Open in new window

with something like this:
OpenMPThreadProc(...)
{
 HANDLE myThread = CreateThread( myStackSize, MyRecursiveFunc() );
 WaitForSingleObject( myThread );
}

Open in new window

But probably I'm wrong with my assumption ... hard to say without testing it :o)

The only other method I can imagine as workaround to search ways to reduce the stack size needed by the recursive function ... but I don't know if this is possible, the only ways to do this IMO is to reduce the amount of data instantiated on the stack by the recursive function, to reduce the recursion depth or to try to find a way to implement the functionality without recursion.

Best regards,

ZOPPO
Avatar of zmau

ASKER

Hi,

Take a look at https://en.wikipedia.org/wiki/OpenMP
Basically OpenMP is a tool to parallelize code into different threads (without actually dealing with threads).
OpenMP opens threads (in the background), and spreads algorithms among the different core.
your code will look something like :
#include <stdio.h>
#include <omp.h>

int main(void)
{
    #pragma omp parallel
    printf("Hello, world.\n");
    return 0;
}
Of course it is mostly relevant for "heavy algorithms code".
The point is that you do not really have control over it, it's actual code, and it's threads.


Thanks
zmau
hm - yes, I know such basics from OpenMP ... but I think I don't understand where the real difference is. Instead of calling 'printf' you could call a function which creates a thread (and wait for it) which calls 'printf', couldn't you, i.e. somehow like this:
void foo( const char* str )
{
	std::thread t{ [str] { printf( str ); } };
	t.join();
}

int main( void )
{
#pragma omp parallel
	foo( "Hello, world.\n" );
	return 0;
}

Open in new window

For me this works the same way as your sample.

To use Windows thread (with the ability to use a specific stack size) 'foo' could be implemented somehow like this:
void foo( const char* str )
{
	auto func = [] ( void* ptr ) -> DWORD
	{
		return printf( (const char*)ptr );
	};

	WaitForSingleObject( 
		::CreateThread( nullptr, 0x200000, func, (void*)str, 0, nullptr ), // stack size is set 2 MB
		INFINITE
	);
}

int main( void )
{
#pragma omp parallel
	foo( "Hello, world.\n" );
	return 0;
}

Open in new window

Of course there's no need to use a lambda, I just did it this way since I like lambdas ;o)

ZOPPO
Avatar of zmau

ASKER

Thanks,
I worked for some time to write an answer, and somehow it got lost, so I have to write it all over again  :-( .
My example was too simple so it loos the same (but it isn't - complicated to explain).

My DLL holds 1000 functions, which does complicated calculations and uses OpenMP for many things (sort(), sin(), cosin(), .........).
These functions are being called constantly at a very high rate.
1) The suggested example creates and destroys threads whenever any of my functions is being called. This consumes a lot of CPU. I could of course create a pool,  but why should I do it if OpenMP already does that for me ?
Now lets thing that I wrote my own pool of threads....
2) My code should run on many types of machines (2, 4, 8, 20 cores). So my code should be flexible enough to split the work between all threads for all of the possible cases.  But then again why should I do it if OpenMP already does that for me ?
3) My "threads code" should have many sub functions, and I need to pass them on all of the specific parameters for the different functions. But then again why should I do it if OpenMP already does that for me ?

Does my explanation make sense ?  Am I missing something ?

Thanks again for the great effort.
zmau
Well, yes, it makes sense - but as long as you can't find a way to solve the problem with the insufficient stack-size with OpenMP-threads I think you can only use one of these workarounds:

- find a way to call the recursive functionality within the OpenMP-thread with a bigger stack than present in the OpenMP-thread.
- reduce the needed stack-size in the recursive functionality
- re-implement the recursive functionality in a none-recursive way

All I demonstrated above is about the first one, a way how to allow calling a function which uses a bigger stack-size than the current thread provides. I still think there's no way to specify/change the size of a running thread at runtime, at least I found no possibility yet, neither for OpenMP, std::thread or Win32-API Threads ... and the latter one AFAIK is the only thread-implementation where it's at least at startup possible, to specify a none-default stack-size.

If this is not the way you want to go I think you can solve the problem only by using one of the other two workarounds, but without knowing anything about the recursive functions I cannot tell how this can be done best - probably you can move as many stack-variables/-arrays and/or function parameters as possible to the heap to reduce the stack size needed for each recursive call, and/or it even may be it's possible to re-write the recursive functionality in a non-recursive way ... hard to say without more info about the recursive functionality and its implementation.

Best regards,

ZOPPO
Avatar of zmau

ASKER

Thanks.
1) I was thinking that it might be possible to "allocate memory" and use it as a "new stack" for the DLL's functions (something like "jump to the new stack.. and then switch back to the current stack").
2) The other solution that I can see is to switch to a whole new process - where I control the stack size (and still enjoy OpenMP).

Thanks anyway
if nobody will give me a hint as to how to implement the first idea, I will close the issue.

Bye
zmau
ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial