kuldeep paranjpe
|
Memory release issue after pthread_detach and pthread_cancel
|
kuldeep paranjpe
07/15/2009 8:44 AM
post33805
|
Memory release issue after pthread_detach and pthread_cancel
Hi,
I am trying to create a thread in 'main' process. This thread allocates about 100K memory, sleeps for few seconds and
then releases the memory. 3 such threads are created by the parent process.
After creating each thread parent process sleeps for some time and calls pthread_detach() and pthread_cancel() on
particular 'tid'.
When I do 'pidin m' for that process, I could see the memory of parent process goes on increasing. with each thread
create the parent process starts with new memory offset(actual + allocated). i.e when thread finishes it does not
liberate the complete memory and parent process does not return to it's original value
The logs says that;
parent process starts with about 36K, and after finishing all the threads it ends up acquiring 456K.
pthread_detach() synopsis says '"When a detached thread terminates, all system resources allocated to that thread are
immediately reclaimed."
OS should destroy all the thread stack once its function is done and is cancelled(also pidin dosen't show that thread).
from where this memory is getting accumulated in parent process? OR is there any other way to clean up the thread stack?
??
Here is the sample program;
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/resource.h>
static void* cliente(void *datos)
{
while(true)
{
//Allocating dummy memory of about 100K
char *buff= new char[100000];
sleep(20);
//releasing memory
delete [] buff;
buff=NULL;
}
}
int main()
{
int ret1;
ret1=0;
pthread_t mythread[4];
while(ret1 < 3)
{
//create thread
if(!pthread_create((pthread_t *)&mythread[ret1],NULL,cliente,NULL))
{
perror("pthread_create");
}
//dummy sleep
sleep(60);
//detach the thread
int ret = pthread_detach((pthread_t)mythread[ret1]);
if(EOK == ret)
{
printf("Thread %d got detached\n",mythread[ret1]);
fflush(stdout);
}
//cancel the thread
int iRet = pthread_cancel((pthread_t)mythread[ret1]);
if(EOK == iRet)
{
printf("Thread %d got cancelled\n",mythread[ret1]);
fflush(stdout);
}
mythread[ret1] = NULL;
ret1++;
}
while(true)
{
}
return EXIT_SUCCESS;
}
|
|
|
Mario Charest
|
RE: Memory release issue after pthread_detach and pthread_cancel
|
Mario Charest
07/15/2009 8:47 AM
post33807
|
RE: Memory release issue after pthread_detach and pthread_cancel
What verion of the OS are you using. With 6.3.2 the heap can only grow it never shrinks. On 6.4.X the heap can shrink
and the memory is return to the OS. Check the documentation.
-----Original Message-----
From: kuldeep paranjpe [mailto:community-noreply@qnx.com]
Sent: Wednesday, July 15, 2009 8:45 AM
To: ostech-core_os
Subject: Memory release issue after pthread_detach and pthread_cancel
Hi,
I am trying to create a thread in 'main' process. This thread allocates about 100K memory, sleeps for few seconds and
then releases the memory. 3 such threads are created by the parent process.
After creating each thread parent process sleeps for some time and calls pthread_detach() and pthread_cancel() on
particular 'tid'.
When I do 'pidin m' for that process, I could see the memory of parent process goes on increasing. with each thread
create the parent process starts with new memory offset(actual + allocated). i.e when thread finishes it does not
liberate the complete memory and parent process does not return to it's original value
The logs says that;
parent process starts with about 36K, and after finishing all the threads it ends up acquiring 456K.
pthread_detach() synopsis says '"When a detached thread terminates, all system resources allocated to that thread are
immediately reclaimed."
OS should destroy all the thread stack once its function is done and is cancelled(also pidin dosen't show that thread).
from where this memory is getting accumulated in parent process? OR is there any other way to clean up the thread stack?
??
Here is the sample program;
#include <cstdlib>
#include <iostream>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/resource.h>
static void* cliente(void *datos)
{
while(true)
{
//Allocating dummy memory of about 100K
char *buff= new char[100000];
sleep(20);
//releasing memory
delete [] buff;
buff=NULL;
}
}
int main()
{
int ret1;
ret1=0;
pthread_t mythread[4];
while(ret1 < 3)
{
//create thread
if(!pthread_create((pthread_t *)&mythread[ret1],NULL,cliente,NULL))
{
perror("pthread_create");
}
//dummy sleep
sleep(60);
//detach the thread
int ret = pthread_detach((pthread_t)mythread[ret1]);
if(EOK == ret)
{
printf("Thread %d got detached\n",mythread[ret1]);
fflush(stdout);
}
//cancel the thread
int iRet = pthread_cancel((pthread_t)mythread[ret1]);
if(EOK == iRet)
{
printf("Thread %d got cancelled\n",mythread[ret1]);
fflush(stdout);
}
mythread[ret1] = NULL;
ret1++;
}
while(true)
{
}
return EXIT_SUCCESS;
}
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33805
|
|
|
Elena Laskavaia
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Elena Laskavaia
07/15/2009 10:04 AM
post33828
|
Re: Memory release issue after pthread_detach and pthread_cancel
"System resources" that suppose to be deallocated does not include heap
memory since memory heap is managed separately.
If objects are properly deleted heap memory can be reclaimed for re-use.
Total heap may not shrink though especially if it is heavily fragmented
(and depends on OS version).
kuldeep paranjpe wrote:
> Hi,
>
> I am trying to create a thread in 'main' process. This thread allocates about 100K memory, sleeps for few seconds and
then releases the memory. 3 such threads are created by the parent process.
> After creating each thread parent process sleeps for some time and calls pthread_detach() and pthread_cancel() on
particular 'tid'.
> When I do 'pidin m' for that process, I could see the memory of parent process goes on increasing. with each thread
create the parent process starts with new memory offset(actual + allocated). i.e when thread finishes it does not
liberate the complete memory and parent process does not return to it's original value
>
> The logs says that;
> parent process starts with about 36K, and after finishing all the threads it ends up acquiring 456K.
>
> pthread_detach() synopsis says '"When a detached thread terminates, all system resources allocated to that thread are
immediately reclaimed."
>
> OS should destroy all the thread stack once its function is done and is cancelled(also pidin dosen't show that thread)
.
>
> from where this memory is getting accumulated in parent process? OR is there any other way to clean up the thread
stack???
>
> Here is the sample program;
>
> #include <cstdlib>
> #include <iostream>
> #include <stdio.h>
> #include <pthread.h>
> #include <errno.h>
> #include <unistd.h>
> #include <stdlib.h>
> #include <sys/resource.h>
>
> static void* cliente(void *datos)
> {
> while(true)
> {
> //Allocating dummy memory of about 100K
> char *buff= new char[100000];
> sleep(20);
> //releasing memory
> delete [] buff;
> buff=NULL;
> }
> }
>
> int main()
> {
> int ret1;
> ret1=0;
> pthread_t mythread[4];
>
> while(ret1 < 3)
> {
> //create thread
> if(!pthread_create((pthread_t *)&mythread[ret1],NULL,cliente,NULL))
> {
> perror("pthread_create");
> }
> //dummy sleep
> sleep(60);
> //detach the thread
> int ret = pthread_detach((pthread_t)mythread[ret1]);
> if(EOK == ret)
> {
> printf("Thread %d got detached\n",mythread[ret1]);
> fflush(stdout);
> }
> //cancel the thread
> int iRet = pthread_cancel((pthread_t)mythread[ret1]);
> if(EOK == iRet)
> {
> printf("Thread %d got cancelled\n",mythread[ret1]);
> fflush(stdout);
> }
> mythread[ret1] = NULL;
> ret1++;
> }
> while(true)
> {
> }
> return EXIT_SUCCESS;
> }
>
>
>
>
>
>
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post33805
>
|
|
|
Shiv Nagarajan(deleted)
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Shiv Nagarajan(deleted)
07/15/2009 10:04 AM
post33829
|
Re: Memory release issue after pthread_detach and pthread_cancel
The memory allocation has changed a little from 6.3.2 to 6.4.x.
But specifically what you are trying to do, can be achieved, I think,
in 6.3.2 by just using some environment variables.
specifically you can use
MALLOC_MEMORY_HOLD=0
(this doesnt hold on to memory in the heap, when blocks are freed and
"can" be released to the system using an underlying munmap call)
or more individually
MALLOC_ARENA_CACHE_MAXBLK=0
MALLOC_ARENA_CACHE_MAXSZ=0
which reduces the size of cached memory blocks inside the heap when
memory is free-ed.
both 6.3.2 and 6.4.x do shrink the heap, but the settings like these
variables control what is freed and when.
in 6.3.2 by default the MAXBLK = 8, so we will cached "8" arena blocks
(this would be 8 blocks of memory that we went to the system with mmap
for).
the size allows you to configure the total size of the
malloc_arena_cache to the specified total size.
let me know if this works for you.
shiv
On Wed, 2009-07-15 at 08:45 -0400, kuldeep paranjpe wrote:
> Hi,
>
> I am trying to create a thread in 'main' process. This thread
> allocates about 100K memory, sleeps for few seconds and then releases
> the memory. 3 such threads are created by the parent process.
> After creating each thread parent process sleeps for some time and
> calls pthread_detach() and pthread_cancel() on particular 'tid'.
> When I do 'pidin m' for that process, I could see the memory of parent
> process goes on increasing. with each thread create the parent process
> starts with new memory offset(actual + allocated). i.e when thread
> finishes it does not liberate the complete memory and parent process
> does not return to it's original value
>
> The logs says that;
> parent process starts with about 36K, and after finishing all the
> threads it ends up acquiring 456K.
>
> pthread_detach() synopsis says '"When a detached thread terminates,
> all system resources allocated to that thread are immediately
> reclaimed."
>
> OS should destroy all the thread stack once its function is done and
> is cancelled(also pidin dosen't show that thread).
>
> from where this memory is getting accumulated in parent process? OR is
> there any other way to clean up the thread stack???
>
> Here is the sample program;
>
> #include <cstdlib>
> #include <iostream>
> #include <stdio.h>
> #include <pthread.h>
> #include <errno.h>
> #include <unistd.h>
> #include <stdlib.h>
> #include <sys/resource.h>
>
> static void* cliente(void *datos)
> {
> while(true)
> {
> //Allocating dummy memory of about 100K
> char *buff= new char[100000];
> sleep(20);
> //releasing memory
> delete [] buff;
> buff=NULL;
> }
> }
>
> int main()
> {
> int ret1;
> ret1=0;
> pthread_t mythread[4];
>
> while(ret1 < 3)
> {
> //create thread
> if(!pthread_create((pthread_t
> *)&mythread[ret1],NULL,cliente,NULL))
> {
> perror("pthread_create");
> }
> //dummy sleep
> sleep(60);
> //detach the thread
> int ret = pthread_detach((pthread_t)mythread[ret1]);
> if(EOK == ret)
> {
> printf("Thread %d got detached\n",mythread[ret1]);
> fflush(stdout);
> }
> //cancel the thread
> int iRet = pthread_cancel((pthread_t)mythread[ret1]);
> if(EOK == iRet)
> {
> printf("Thread %d got cancelled\n",mythread[ret1]);
> ...
View Full Message
|
|
|
kuldeep paranjpe
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
kuldeep paranjpe
07/15/2009 10:19 AM
post33832
|
Re: Memory release issue after pthread_detach and pthread_cancel
Hi,
Thanks for your feedback...
Mario: unfortunately we are still using QNX 6.3.0...we are planning to upgrade, however we can't in the near future do
various stability issues.
Elena: The objects are being properly deleted. The code that I presented above is just the sample code and not the
actual one. In the actual code, nothing is being used on the heap. Everything is on the stack. Still I am facing the
same problem.
Shiv: In the actual code, I am not using malloc. Everything is on the stack.
Does it so happen that when I cancel the threads, the memory gets accumulated in the parent process and not released to
the system? Because this is what seems to be happening.
Awaiting your insights.
Warm Regards,
Kuldeep
|
|
|
Shiv Nagarajan(deleted)
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Shiv Nagarajan(deleted)
07/15/2009 10:21 AM
post33833
|
Re: Memory release issue after pthread_detach and pthread_cancel
calling new.. calls malloc
called delete calls free
there is only one process.. and the threads you are creating are
cancelled.. and the memory they allocate via "new" is allocated on the
heap.
shiv
Wed Jul 15 10:21:38 EDT 2009
--> According to kuldeep paranjpe <--
Hi,
Thanks for your feedback...
Mario: unfortunately we are still using QNX 6.3.0...we are planning to
upgrade, however we can't in the near future do various stability
issues.
Elena: The objects are being properly deleted. The code that I presented
above is just the sample code and not the actual one. In the actual
code, nothing is being used on the heap. Everything is on the stack.
Still I am facing the same problem.
Shiv: In the actual code, I am not using malloc. Everything is on the
stack.
Does it so happen that when I cancel the threads, the memory gets
accumulated in the parent process and not released to the system?
Because this is what seems to be happening.
Awaiting your insights.
Warm Regards,
Kuldeep
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33832
--
****
Shiv Nagarajan,
Kernel Developer, QNX Software Systems,
Ottawa, Canada
****
|
|
|
Shiv Nagarajan(deleted)
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Shiv Nagarajan(deleted)
07/15/2009 10:27 AM
post33835
|
Re: Memory release issue after pthread_detach and pthread_cancel
IN fact if the thread is cancelled between calls to new and delete, the
memory will be "leaked"
shiv
--> According to kuldeep paranjpe <--
Hi,
Thanks for your feedback...
Mario: unfortunately we are still using QNX 6.3.0...we are planning to
upgrade, however we can't in the near future do various stability
issues.
Elena: The objects are being properly deleted. The code that I presented
above is just the sample code and not the actual one. In the actual
code, nothing is being used on the heap. Everything is on the stack.
Still I am facing the same problem.
Shiv: In the actual code, I am not using malloc. Everything is on the
stack.
Does it so happen that when I cancel the threads, the memory gets
accumulated in the parent process and not released to the system?
Because this is what seems to be happening.
Awaiting your insights.
Warm Regards,
Kuldeep
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33832
--
****
Shiv Nagarajan,
Kernel Developer, QNX Software Systems,
Ottawa, Canada
****
|
|
|
kuldeep paranjpe
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
kuldeep paranjpe
07/16/2009 7:44 AM
post33889
|
Re: Memory release issue after pthread_detach and pthread_cancel
Is there any way to avoid such leak???
|
|
|
Shiv Nagarajan(deleted)
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Shiv Nagarajan(deleted)
07/16/2009 9:20 AM
post33901
|
Re: Memory release issue after pthread_detach and pthread_cancel
Either use cancellation handlers or don't use pthread cancel. You can implement a different cleanup mechanism using
other norification mechanisms. It would mean code change on your end.
Shiv
Shiv Nagarajan
Kernel developer, QNX Software Systems
Canada
----- Original Message -----
From: kuldeep paranjpe <community-noreply@qnx.com>
To: ostech-core_os <post33889@community.qnx.com>
Sent: Thu Jul 16 07:44:50 2009
Subject: Re: Memory release issue after pthread_detach and pthread_cancel
Is there any way to avoid such leak???
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33889
|
|
|
Mario Charest
|
RE: Memory release issue after pthread_detach and pthread_cancel
|
Mario Charest
07/15/2009 10:29 AM
post33836
|
RE: Memory release issue after pthread_detach and pthread_cancel
I like this behavior because one can run the software for a few days and then you get the idea of the maximum memory
usage. If the memory would return to the OS it becomes much harder to find that one of million scenario when the
machine runs out of memory.
If you don't like this behavior you could use your own object allocator which would be based on mmap().
-----Original Message-----
From: kuldeep paranjpe [mailto:community-noreply@qnx.com]
Sent: Wednesday, July 15, 2009 10:20 AM
To: ostech-core_os
Subject: Re: Memory release issue after pthread_detach and pthread_cancel
Does it so happen that when I cancel the threads, the memory gets accumulated in the parent process and not released to
the system? Because this is what seems to be happening.
Awaiting your insights.
Warm Regards,
Kuldeep
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33832
|
|
|
Elena Laskavaia
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Elena Laskavaia
07/15/2009 10:53 AM
post33839
|
Re: Memory release issue after pthread_detach and pthread_cancel
How is it allocated on stack? You should provide example on how it is
allocated in real code. As Shiv mentioned if you are using new and
delete it is heap.
Object is allocated on stack if you have something like
foo(int l) {
A object; // one object of type A
B arr[l]; // l objects of type B (dynamic size)
}
or if you use alloca
In this case you don't actually do anything to deallocate it - it
happens when functions is out of scope;
kuldeep paranjpe wrote:
> Hi,
> Thanks for your feedback...
>
> Mario: unfortunately we are still using QNX 6.3.0...we are planning to upgrade, however we can't in the near future
do various stability issues.
>
> Elena: The objects are being properly deleted. The code that I presented above is just the sample code and not the
actual one. In the actual code, nothing is being used on the heap. Everything is on the stack. Still I am facing the
same problem.
>
> Shiv: In the actual code, I am not using malloc. Everything is on the stack.
>
> Does it so happen that when I cancel the threads, the memory gets accumulated in the parent process and not released
to the system? Because this is what seems to be happening.
>
> Awaiting your insights.
>
> Warm Regards,
> Kuldeep
>
>
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post33832
>
>
|
|
|
kuldeep paranjpe
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
kuldeep paranjpe
07/15/2009 11:58 AM
post33848
|
Re: Memory release issue after pthread_detach and pthread_cancel
In actual code some maps and vectors are being created on thread stack which are local to the thread and these are
timely erased and cleared. also there exists some class objects (e.g. Cfoo o_Cfoo )which are local to those threads.
There is no chance of dynamic memory allocation as such, as no malloc/new are being used (...I don't have any idea how
maps and vectors internally allocate the memory)
But as per my understanding if there exists some thread stack when thread is in action..if it is cancelled by it's
parent process at any instance..the memory should be taken away by system, i.e. its stack should be deleted by OS...or
whatever
NB: I can't give here actual code due to some security reasons
|
|
|
Mario Charest
|
RE: Memory release issue after pthread_detach and pthread_cancel
|
Mario Charest
07/15/2009 12:03 PM
post33849
|
RE: Memory release issue after pthread_detach and pthread_cancel
-----Original Message-----
From: kuldeep paranjpe [mailto:community-noreply@qnx.com]
Sent: Wednesday, July 15, 2009 11:58 AM
To: ostech-core_os
Subject: Re: Memory release issue after pthread_detach and pthread_cancel
In actual code some maps and vectors are being created on thread stack
No, the object in the maps/vectors are in the heap. It's not because you declare the object on the stack that objects
allocated within it are on the stack.
which are local to the thread and these are timely erased and cleared. also there exists some class objects (e.g. Cfoo
o_Cfoo )which are local to those threads. There is no chance of dynamic memory allocation as such, as no malloc/new are
being used (...I don't have any idea how maps and vectors internally allocate the memory)
It used new / delete ;-)
But as per my understanding if there exists some thread stack when thread is in action..if it is cancelled by it's
parent process at any instance..the memory should be taken away by system, i.e. its stack should be deleted by OS...or
whatever
NB: I can't give here actual code due to some security reasons
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33848
|
|
|
Elena Laskavaia
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Elena Laskavaia
07/15/2009 12:13 PM
post33850
|
Re: Memory release issue after pthread_detach and pthread_cancel
Run your example with IDE's memory analysis tool - you will see if
object allocated in heap and what happened to them (are they leaks or not).
kuldeep paranjpe wrote:
> In actual code some maps and vectors are being created on thread stack which are local to the thread and these are
timely erased and cleared. also there exists some class objects (e.g. Cfoo o_Cfoo )which are local to those threads.
There is no chance of dynamic memory allocation as such, as no malloc/new are being used (...I don't have any idea how
maps and vectors internally allocate the memory)
> But as per my understanding if there exists some thread stack when thread is in action..if it is cancelled by it's
parent process at any instance..the memory should be taken away by system, i.e. its stack should be deleted by OS...or
whatever
>
> NB: I can't give here actual code due to some security reasons
>
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post33848
>
>
|
|
|
kuldeep paranjpe
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
kuldeep paranjpe
07/15/2009 12:56 PM
post33851
|
Re: Memory release issue after pthread_detach and pthread_cancel
Ya..I guess what Shiv and you guys told was right...I could really see the memory growing by "new offset" in System
Malloc information...
But what can someone do if the thread has acquired some memory by malloc/new/map/vector or anything...and an external
event abruptly triggers pthread_detach() and pthread_cancel()????
The memory will never be released...I guess this is what is happening
Thanks to you guys! :-)
|
|
|
Martin Doane
|
RE: Memory release issue after pthread_detach and pthread_cancel
|
Martin Doane
07/15/2009 12:59 PM
post33854
|
RE: Memory release issue after pthread_detach and pthread_cancel
pthread_cleanup_push()
pthread_cleanup_pop()
> -----Original Message-----
> From: kuldeep paranjpe [mailto:community-noreply@qnx.com]
> Sent: Wednesday, July 15, 2009 12:56 PM
> To: ostech-core_os
> Subject: Re: Memory release issue after pthread_detach and
> pthread_cancel
>
> Ya..I guess what Shiv and you guys told was right...I could really see
> the memory growing by "new offset" in System Malloc information...
> But what can someone do if the thread has acquired some memory by
> malloc/new/map/vector or anything...and an external event abruptly
> triggers pthread_detach() and pthread_cancel()????
> The memory will never be released...I guess this is what is happening
>
> Thanks to you guys! :-)
>
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post33851
|
|
|
Will Miles
|
Re: RE: Memory release issue after pthread_detach and pthread_cancel
|
Will Miles
07/15/2009 2:20 PM
post33859
|
Re: RE: Memory release issue after pthread_detach and pthread_cancel
The pthread cleanup functions are implemented under the hood using a longjmp()-style solution - it's nigh-impossible to
make it do proper automatic cleanup of stack-allocated C++ objects. In a broad sense, using C++ and pthread_cancel() /
will/ get you in to trouble.
The only really practical solution if you're using C++ is to avoid using pthread_cancel(). Ultimately we ended up
writing a library that uses a signal to request cancellation on a target thread, and liberal usage of a call to check
whether this signal has arrived (particularly after blocking calls) - if the signal was triggered, we throw an exception
, allowing the exception handling code to clean up the stack [as well as allowing catch() blocks to do special-purpose
cleanup if necessary]. The down side is that you have to remember to place cancellation points explicitly in your code.
-Will
|
|
|
Mario Charest
|
RE: RE: Memory release issue after pthread_detach and pthread_cancel
|
Mario Charest
07/15/2009 2:25 PM
post33860
|
RE: RE: Memory release issue after pthread_detach and pthread_cancel
Or you put the thread as a fonction member inside a class that hold all the objects, have the destructor do the
pthread_cancel and then let the rest of the destructor free the object.
I use the POCO library for that type of stuff which has a Runnable class that you inherit from and deal with some of the
thread details.
I believe the class Rennie wrote which is avaiblable as a Project under foundry27 also has this stuff in.
________________________________________
From: Will Miles [community-noreply@qnx.com]
Sent: Wednesday, July 15, 2009 2:20 PM
To: ostech-core_os
Subject: Re: RE: Memory release issue after pthread_detach and pthread_cancel
The pthread cleanup functions are implemented under the hood using a longjmp()-style solution - it's nigh-impossible to
make it do proper automatic cleanup of stack-allocated C++ objects. In a broad sense, using C++ and pthread_cancel() /
will/ get you in to trouble.
The only really practical solution if you're using C++ is to avoid using pthread_cancel(). Ultimately we ended up
writing a library that uses a signal to request cancellation on a target thread, and liberal usage of a call to check
whether this signal has arrived (particularly after blocking calls) - if the signal was triggered, we throw an exception
, allowing the exception handling code to clean up the stack [as well as allowing catch() blocks to do special-purpose
cleanup if necessary]. The down side is that you have to remember to place cancellation points explicitly in your code.
-Will
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33859
|
|
|
Will Miles
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Will Miles
07/16/2009 12:44 PM
post33962
|
Re: Memory release issue after pthread_detach and pthread_cancel
Hi Mario,
Sure, it'd work very well, as long as you're absolutely certain that
when the pthread_cancel goes through you have no C++ objects that
require their own destructors are allocated on the stack in that thread.
Personally, I like to use RAII patterns for managing things like mutexes
by using guard objects. I find that allocating guards on the stack is
very practical - it makes it vastly simpler to manage lock scoping.
pthread_cancel makes a total hash of the way those work, since if you
get hit with a cancel while holding the lock, the destructor on the
guard object will never run. Forcing those temporary stack allocations
out to higher-scope objects feels like an encapsulation violation to
me, requiring some aspect of a function's local state to live in the
object it's attached to. It'd also require serialization at a higher
level - we use an event-driven model for much of our architecture,
which in turn means that having many threads in the same function is
the norm rather than the exception for us; keeping lists of the worker
threads blocked on a condvar that might need to release the mutex if
killed is certainly doable, but seemed like more work than just
implementing a C++-safe cancellation mechanism that ensured that
stack-allocated objects would get appropriately destructed.
The bottom line is that any way you slice it, stack-allocated C++
objects and pthread_cancel don't work together. This leaves the
programmer with two possible options:
a) avoid using pthread_cancel (potentially by implementing your own
cancellation scheme);
or
b) don't allocate any C++ objects on the stack (potentially by ensuring
that all C++ objects used by code called on the relevant thread are
held by a larger-scope object).
Ultimately it depends on how you use C++. :)
-Will
On Wed, 15 Jul 2009 14:26:02 -0400 (EDT)
Mario Charest <community-noreply@qnx.com> wrote:
>
> Or you put the thread as a fonction member inside a class that hold all the objects, have the destructor do the
pthread_cancel and then let the rest of the destructor free the object.
>
> I use the POCO library for that type of stuff which has a Runnable class that you inherit from and deal with some of
the thread details.
>
> I believe the class Rennie wrote which is avaiblable as a Project under foundry27 also has this stuff in.
|
|
|
kuldeep paranjpe
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
kuldeep paranjpe
07/16/2009 1:11 PM
post33963
|
Re: Memory release issue after pthread_detach and pthread_cancel
If not pthread_cancel...I think pthread_exit() should do the job!
the thread in action should gracefully exit on it's own...
|
|
|
Shiv Nagarajan(deleted)
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Shiv Nagarajan(deleted)
07/16/2009 1:16 PM
post33964
|
Re: Memory release issue after pthread_detach and pthread_cancel
its not really the thread exit that is the issue. It is the fact that
memory that is allocated is from the heap is not freed back and the
thread that has a reference to this memory is no longer around to clean
this up. Thats what results in the leak
shiv
Thu Jul 16 13:15:50 EDT 2009
--> According to kuldeep paranjpe <--
If not pthread_cancel...I think pthread_exit() should do the job!
the thread in action should gracefully exit on it's own...
_______________________________________________
OSTech
http://community.qnx.com/sf/go/post33963
--
****
Shiv Nagarajan,
Kernel Developer, QNX Software Systems,
Ottawa, Canada
****
|
|
|
Neil Schellenberger(deleted)
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Neil Schellenberger(deleted)
07/16/2009 1:37 PM
post33969
|
Re: Memory release issue after pthread_detach and pthread_cancel
One underlying problem here is that the C++ standard does not provide
any guidance on what to do in the presence of threads. And the POSIX
specification does not require any specific special C++ behaviour for
pthread_cancel(). Our implementation doesn't actually rely on
setjmp/longjmp (it actually effectively hooks in to the atexit()
handling), but the net result is the same: C++ unwinding does not occur.
As a previous poster points out, it is likely to be very tricky indeed
to get POSIX thread cancellation and C++ to work nicely with each other.
One workaround would be to arrange for some other OOB signalling
mechanism to set a thread-visible flag which is periodically checked
and, when set, causes some sort of exception to be raised. This also
helps to control cancellation state: most library calls (e.g. member
functions of map, multiset, etc.) are not cancellation-safe in any case,
so Bad Things(tm) are likely to happen anyway. (POSIX cancellation is
really only actually useful in a very limited number of scenarios.)
On Thu, 2009-07-16 at 13:16 -0400, Shiv Nagarajan wrote:
> its not really the thread exit that is the issue. It is the fact that
> memory that is allocated is from the heap is not freed back and the
> thread that has a reference to this memory is no longer around to clean
> this up. Thats what results in the leak
>
> shiv
> Thu Jul 16 13:15:50 EDT 2009
>
> --> According to kuldeep paranjpe <--
> If not pthread_cancel...I think pthread_exit() should do the job!
> the thread in action should gracefully exit on it's own...
>
> _______________________________________________
> OSTech
> http://community.qnx.com/sf/go/post33963
>
>
|
|
|
Will Miles
|
Re: Memory release issue after pthread_detach and pthread_cancel
|
Will Miles
12/20/2009 9:24 PM
post44173
|
Re: Memory release issue after pthread_detach and pthread_cancel
Hi,
My apologies for necroposting, but I've recently been forced to reconsider the issue and wanted to leave a trackback for
anyone else facing this problem.
Our original implementation worked more-or-less the way Neil described: we used a signal targeted at a specific thread
to carry a cancellation request, and then relied on interspersing our own check_cancel() calls at strategic points in
our code. If the signal had been tripped, check_cancel() would throw a C++ exception, forcing a stack unwind. Using a
signal seemed like a particularly clever choice because it would induce an EINTR unblock if the thread was waiting for
something. The resulting code would often look something like:
LockGuard lg(mutex);
while (condition == false) {
check_cancel();
pthread_cond_wait(&condvar, &mutex);
check_cancel();
}
This arrangement seemed to work pretty well for a few years. Recently, however, we ran in to a test machine where
threads would seemingly get stuck and miss the cancellation request somehow. It turned out that what was happening was
that the thread was getting interrupted AFTER the first check_cancel(), but BEFORE the blocking call - so the signal
handler would run without causing an EINTR, and the thread would just end up blocked instead of terminating. The
obvious fix - just try the cancel a couple times - still didn't work; because of other issues on our test rack the
subsequent cancel attempts still vanished because the poor target thread was getting CPU starved.
To mitigate this hole, we were forced to reconsider pthread_cancel() - it seems it is the only mechanism that will /
guarantee/ that a thread will terminate in a well-defined way without any race conditions. Unfortunately, this brought
us back to the original poster's problem, where C++ objects on the stack would not be properly destructed.
We did ultimately find a mechanism of transforming a POSIX cancellation request into a C++ exception throw, though it
requires a bit of black magic. The basic approach is to:
a) Run threads with POSIX cancellation normally set to PTHREAD_CANCEL_DISABLE.
b) Only enable cancellation at your own explicitly added cancellation test points, or around blocking C library calls
that you can be confident have no side effects (such as internally allocating memory). Most places we found that
threads needed to be cancelable from (sleep()s, pthread_cond_wait()s, MsgSend()s, InterruptWait()s, etc.) seem to be in
this category at the present time.
c) Before you enable cancellation, capture the CPU state and stack frame pointer and cache this information. Then, bind
a pthread_cleanup handler that first restores the CPU state, adjusts its own stack frame so that it will return
directly to the original calling function where the capture took place (stepping over the library call stack frames),
then throws the C++ exception.
While this seems to be functional, it is unfortunately a bit fragile - the cleanup handler code will be necessarily
machine and compiler specific. Right now I have a working implementation for x86 on QNX 6.3.2 (using GCC 3.3.5). Ping
me if you want the source code.
Good luck threaded C++ users!
-Will
|
|
|
|