pthread memory leaks

J

jakash3

I'm experimenting with signals and conditional variables to implement
thread suspension. The following appears to execute without any
problems but valgrind reports memory leaks.
What can I do to stop the memory leaks? Is there some type of pthread
related memory free function I'm forgetting?

=================================
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <cstdlib>

pthread_mutex_t m;
pthread_cond_t c;

void freeze(int sig) {
pthread_mutex_lock(&m);
pthread_cond_wait(&c, &m);
pthread_mutex_unlock(&m);
}
void quit(int sig) { pthread_exit(0); }

void* tfunc(void* param) {
while (1) {
puts("hi");
sleep(1);
}
return NULL;
}

int main() {
pthread_mutex_init(&m, NULL);
pthread_cond_init(&c, NULL);
struct sigaction s;
memset(&s, 0, sizeof(struct sigaction));

/*
* SIGUSR1 signal for thread suspend
* and SIGUSR2 signal for thread exit
*/
s.sa_handler = &freeze;
s.sa_flags = SA_SIGINFO;
sigaction(SIGUSR1, &s, NULL);
s.sa_handler = &quit;
sigaction(SIGUSR2, &s, NULL);

pthread_t t;
pthread_create(&t, NULL, &tfunc, (void*)NULL);
pthread_detach(t);
getchar();
/* suspend */
pthread_kill(t, SIGUSR1);
getchar();
/* resume */
pthread_cond_signal(&c);
getchar();
/* terminate */
pthread_kill(t, SIGUSR2);
pthread_mutex_destroy(&m);
pthread_cond_destroy(&c);
return 0;
}
=================================

valgrind output:
=================================
==2993==
==2993== HEAP SUMMARY:
==2993== in use at exit: 144 bytes in 1 blocks
==2993== total heap usage: 1 allocs, 0 frees, 144 bytes allocated
==2993==
==2993== LEAK SUMMARY:
==2993== definitely lost: 0 bytes in 0 blocks
==2993== indirectly lost: 0 bytes in 0 blocks
==2993== possibly lost: 144 bytes in 1 blocks
==2993== still reachable: 0 bytes in 0 blocks
==2993== suppressed: 0 bytes in 0 blocks
==2993== Rerun with --leak-check=full to see details of leaked memory
==2993==
==2993== For counts of detected and suppressed errors, rerun with: -v
==2993== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from
8)
=================================
 
I

Ian Collins

I'm experimenting with signals and conditional variables to implement
thread suspension. The following appears to execute without any
problems but valgrind reports memory leaks.
What can I do to stop the memory leaks? Is there some type of pthread
related memory free function I'm forgetting?

You'd be better of on a Linux or Unix group for this kind of question.
However there are a few C++ specific issues:
=================================
#include<pthread.h>
#include<signal.h>
#include<unistd.h>
#include<cstdio>
#include<cstring>
#include<cstdlib>

pthread_mutex_t m;
pthread_cond_t c;

void freeze(int sig) {
pthread_mutex_lock(&m);
pthread_cond_wait(&c,&m);
pthread_mutex_unlock(&m);
}
void quit(int sig) { pthread_exit(0); }

void* tfunc(void* param) {
while (1) {
puts("hi");

As you have included the C++ versions of the C library headers, fictions
form them like puts should be written std::puts. Some compilers put
them in the namespace, while others (like gcc) declare them in and out
of the namespace, which is a pain.
sleep(1);
}
return NULL;
}

This are all assigned to C function pointers, so they should be declared
as extern "C" (gcc ignores this).

valgrind output:
=================================
==2993==
==2993== HEAP SUMMARY:
==2993== in use at exit: 144 bytes in 1 blocks
==2993== total heap usage: 1 allocs, 0 frees, 144 bytes allocated
==2993==
==2993== LEAK SUMMARY:
==2993== definitely lost: 0 bytes in 0 blocks
==2993== indirectly lost: 0 bytes in 0 blocks
==2993== possibly lost: 144 bytes in 1 blocks

Note this is an in use block, not an actual leak. Probably an internal
I/O buffer.
 
J

jakash3

Note this is an in use block, not an actual leak. Probably an internal
I/O buffer.

Thank you for responding.
You're right, I didn't look at the output close enough. It reported
144 bytes possibly, not definitely, lost.
This is good, because I'm making a posix/win32 class for
multithreading.
 
I

Ian Collins

Thank you for responding.
You're right, I didn't look at the output close enough. It reported
144 bytes possibly, not definitely, lost.
This is good, because I'm making a posix/win32 class for
multithreading.

Have you looked at boost thread?
 
J

jakash3

Have you looked at boost thread?

Yes, It doesn't appear to have thread suspension. I hope to implement
this for my thread class:

class Thread {
public:
#ifdef _WIN32
HANDLE tid;
#else
pthread_t tid;
#endif
void* (*sub)(void*);
Thread();
~Thread();
Thread(void* (*tfunc)(void*));
Thread& operator= (void* (*tfunc)(void*));
Thread& operator= (Thread t);
bool operator!= (void* (*tfunc)(void*));
bool operator!= (Thread t);
bool operator== (void* (*tfunc)(void*));
bool operator== (Thread t);
bool start(void* param = 0);
void* term(void* (*quit)(void*) = 0, void* param = 0);
bool stop();
bool cont();
bool join(void ** ret);
};
 
S

Stuart Redmann

I'm experimenting with signals and conditional variables to implement
thread suspension.

[snip]

Just out of curiosity: When I tried to write some platform-independent
code that worked with multiple threads I was quite amazed that there
is no equivalent for Win32 Events under Unix. I guess that this is the
problem you are trying to deal with? (sorry, I know too little of the
pthread API to fully understand your code)

Thanks,
Stuart
 
A

Adam Skutt

I'm experimenting with signals and conditional variables  to implement
thread suspension.

Don't. It will only work on Linux, and even then, you'll run into
many subtle and difficult to debug issues. Threads and signals simply
do not mix, period. Even if you get your internal signal delivery
working, you still have to make sure you properly cope with externally
delivered signals as well, which can be tricky or outright
impossible. As an added bonus, I'm ignoring the inherit difficult of
writing correct threaded code with shared state where you can
arbitrarily suspend processes. For example, what happens if you're
holding a mutex and get sent the suspend signal? If you don't block
it while holding the mutex, your code will deadlock.

Make sure you really need suspension before you proceed further
(legitimate cases for halting execution in this fashion are rare). If
you really need it, make sure it cannot be done cooperatively or in
another fashion. If you absolutely must have suspension, the only
reliable way to do is to switch to a multi-process model and use the
builtin SIGSTOP / SIGCONT signals. Note that even those may not quite
work in the way you expect.
valgrind output:
=================================
==2993==
==2993== HEAP SUMMARY:
==2993==     in use at exit: 144 bytes in 1 blocks
==2993==   total heap usage: 1 allocs, 0 frees, 144 bytes allocated
==2993==
==2993== LEAK SUMMARY:
==2993==    definitely lost: 0 bytes in 0 blocks
==2993==    indirectly lost: 0 bytes in 0 blocks
==2993==      possibly lost: 144 bytes in 1 blocks
==2993==    still reachable: 0 bytes in 0 blocks
==2993==         suppressed: 0 bytes in 0 blocks
==2993== Rerun with --leak-check=full to see details of leaked memory
==2993==
==2993== For counts of detected and suppressed errors, rerun with: -v
==2993== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 21 from
8)
=================================

Your code doesn't have any obvious memory leaks. I'm pretty sure the
144 bytes in question are TLS releated. glibc is awful about cleaning
up after its own messes.

Adam
 
J

Jorgen Grahn

Don't. It will only work on Linux, and even then, you'll run into
many subtle and difficult to debug issues. Threads and signals simply
do not mix, period. Even if you get your internal signal delivery
working, you still have to make sure you properly cope with externally
delivered signals as well, which can be tricky or outright
impossible.

A short offtopic question to that: with signals being such an integral
part of Linux, aren't you really saying Linux and threads don't mix?
Or are you taking differences beween Linux and other Unixes into
account here?

I'm asking because I recently read an article where the author
asserted that mixing signals and pthreads [specifically on Linux] is
much simpler than people think. (No, I don't have the URL handy, and
no, I don't trust that author absolutely.)

/Jorgen
 
M

Miles Bader

Jorgen Grahn said:
A short offtopic question to that: with signals being such an integral
part of Linux, aren't you really saying Linux and threads don't mix?
Or are you taking differences beween Linux and other Unixes into
account here?

AFAIK, it's not that you can't use them together at all, it's just that
you have to be aware of certain limitations on what is guaranteed (so
relying on what seems to happen in practice on a given implementation
might not be very portable).

Signals are a "rough" tool, threads are a "fine" one, and the
intersection is a bit fuzzy... if fuzzy's OK, then no prob, but...

-miles
 
I

Ian Collins

A short offtopic question to that: with signals being such an integral
part of Linux, aren't you really saying Linux and threads don't mix?
Or are you taking differences beween Linux and other Unixes into
account here?

Maybe you are think of the older Linux Threads (where a thread was
process), used before Linux adopted POSIX threads?
I'm asking because I recently read an article where the author
asserted that mixing signals and pthreads [specifically on Linux] is
much simpler than people think. (No, I don't have the URL handy, and
no, I don't trust that author absolutely.)

It generally is, just so long as you don't try and use any pthread call
in a signal handler! One of the most convenient uses is to dedicate a
thread to handling the process' signals.
 
A

Adam Skutt

A short offtopic question to that: with signals being such an integral
part of Linux, aren't you really saying Linux and threads don't mix?
Or are you taking differences beween Linux and other Unixes into
account here?

Nope, I'm saying you get to pick one of the two features and use that
feature and not the other. Threads are fine. Signals are fine. Both
is a recipe for disaster.

Moreover, even if you get it working on Linux, it probably won't work
well on any other UNIX. Signal handling semantics for threads are
horribly ill defined in several ways:
* Systems are free to use certain signals to implement threading
functionality, but there's no way to figure out what they are at
runtime.
* The behavior between cancellation and signal handling is terribly
ill-defined. Even Linux has races here that can cause the cancellation
to get lost. It also radically alters what you can and cannot do in a
signal handler. Cancellation is probably best avoided in C++ anyway
(it's incompatible with exceptions and RAII), but it serves to
illustrate the problem, and some of the signal issues occur even when
not using cancellation. http://www.slamb.org/projects/cancellation_tests/
contains a brief summary of the issues.
* Historical bugs and other implementation issues, like the
LinuxThreads signal alt stack bug, which means signals have to be
masked out whenever you call pthread_create() until the child thread
creates its own alt stack. Good luck tracking all of these issues
down.
I'm asking because I recently read an article where the author
asserted that mixing signals and pthreads [specifically on Linux] is
much simpler than people think. (No, I don't have the URL handy, and
no, I don't trust that author absolutely.)

It's one of those things that sounds simple but turns out not to be in
practice. The issues aren't the least bit obvious and require careful
thought; the fact that no one has a 100% working, bug free
implementation should tell you how complicated it really is!

Adam
 
A

Adam Skutt

It generally is, just so long as you don't try and use any pthread call
in a signal handler! One of the most convenient uses is to dedicate a
thread to handling the process' signals.

Which is great if you just want to ensure external signals get
consistently directed to a safe place. It doesn't solve the problem
in general, however, and doesn't enable the use of signals for inter-
thread communication like the original posted wished to do.

Adam
 
N

none

Yes, It doesn't appear to have thread suspension. I hope to implement
this for my thread class:

Boost thread has designed decisions in its interface. I would say
that most of these design decisions are to encourage the users
to use multi-threading in a saner and safer manner than when starting
with the full low-level capabilities of pthread or Windows threads.

For example:
class Thread {
public:
#ifdef _WIN32
HANDLE tid;
#else
pthread_t tid;
#endif
void* (*sub)(void*);
Thread();
~Thread();
Thread(void* (*tfunc)(void*));
Thread& operator= (void* (*tfunc)(void*));
Thread& operator= (Thread t);

Please clarify what you intend here? Is this a normal assignment
operator? If so, what does it mean to "assign" an existing thread to
another?

You are defining an operator= without defining a copy-constructor
which is a typical no-no, unless you really can explain why.

If you define a copy-constructor, you also need to really understand
what it means.

Note: boost thread clearly define them as move operations, not copies.

And you would probably need to either pass by reference or need that
copy constructor.
 
C

Chris M. Thomasson

Stuart Redmann said:
I'm experimenting with signals and conditional variables to implement
thread suspension.

[snip]

Just out of curiosity: When I tried to write some platform-independent
code that worked with multiple threads I was quite amazed that there
is no equivalent for Win32 Events under Unix.

FWIW, Windows events can be emulated under POSIX Threads...

I guess that this is the
problem you are trying to deal with? (sorry, I know too little of the
pthread API to fully understand your code)

IPC aside for a moment, one could try something simple like the following
pseudo-code for a windows auto-reset event:
_______________________________________________________
struct win_auto_reset_event
{
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
bool m_set; // = true/false


void set()
{
pthread_mutex_lock(&m_mutex);
m_set = true;
pthread_mutex_unlock(&m_mutex);
pthread_cond_signal(&m_cond);
}


void wait()
{
pthread_mutex_lock(&m_mutex);
while (! m_set) pthread_cond_wait(&m_cond, &m_mutex);
m_set = false;
pthread_mutex_unlock(&m_mutex);
}
};
_______________________________________________________




and this pseudo-code for a windows manual-reset event:
_______________________________________________________
struct win_manual_reset_event
{
pthread_mutex_t m_mutex;
pthread_cond_t m_cond;
bool m_set; // = true/false


void set()
{
pthread_mutex_lock(&m_mutex);
m_set = true;
pthread_mutex_unlock(&m_mutex);
pthread_cond_broadcast(&m_cond);
}


void reset()
{
pthread_mutex_lock(&m_mutex);
m_set = false;
pthread_mutex_unlock(&m_mutex);
}


void wait()
{
pthread_mutex_lock(&m_mutex);
while (! m_set) pthread_cond_wait(&m_cond, &m_mutex);
pthread_mutex_unlock(&m_mutex);
}
};
_______________________________________________________
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top