472,358 Members | 1,776 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,358 software developers and data experts.

Posix thread exiting and destructors

Hi

I'm writing a threading class using posix threads on unix with each
thread being run by an object instance. One thing I'm not sure about
is , if I do the following:

myclass::~myclass()
{
:
: do stuff
:
pthread_exit(&status);
}
If I exit the thread at the end of the destructor will all the memory
used for the object be free'd? My suspicion is it won't and I actually
need to exit the thread outside of the object itself, but I thought
I'd check on here first.

Thanks for any help

B2003

Apr 10 '07 #1
23 5464
On 10 Apr, 10:31, "Boltar" <boltar2...@yahoo.co.ukwrote:
Hi

I'm writing a threading class using posix threads on unix with each
thread being run by an object instance. One thing I'm not sure about
is , if I do the following:

myclass::~myclass()
{
:
: do stuff
:
pthread_exit(&status);

}

If I exit the thread at the end of the destructor will all the memory
used for the object be free'd? My suspicion is it won't and I actually
need to exit the thread outside of the object itself, but I thought
I'd check on here first.
All memory used by an object will be freed after the destructor of the
object has been run. Beware that any memory allocated with new should
be deleted, all non-pointer members will be correctly dealt with
automatically. If you are wondering if all memory used by the thread
(such as TLS) will be freed on pthread_exit() you should ask in a
group for POSIX threads since it's not part of the C++ language.

--
Erik Wikström

Apr 10 '07 #2
On Apr 10, 9:38 am, "Erik Wikström" <eri...@student.chalmers.se>
wrote:
All memory used by an object will be freed after the destructor of the
object has been run. Beware that any memory allocated with new should
be deleted, all non-pointer members will be correctly dealt with
automatically. If you are wondering if all memory used by the thread
(such as TLS) will be freed on pthread_exit() you should ask in a
group for POSIX threads since it's not part of the C++ language.
No , I was just concerned about the memory of the object itself. If
the thread exits , will the code that free's the object actually be
called since the execution context no longer exists?

B2003
Apr 10 '07 #3
Boltar wrote:
On Apr 10, 9:38 am, "Erik Wikström" <eri...@student.chalmers.se>
wrote:
>>All memory used by an object will be freed after the destructor of the
object has been run. Beware that any memory allocated with new should
be deleted, all non-pointer members will be correctly dealt with
automatically. If you are wondering if all memory used by the thread
(such as TLS) will be freed on pthread_exit() you should ask in a
group for POSIX threads since it's not part of the C++ language.


No , I was just concerned about the memory of the object itself. If
the thread exits , will the code that free's the object actually be
called since the execution context no longer exists?
Don't call exit there. You'll need to call pthread_join at least.

This is more on topic for news:comp.programming.threads so I suggest you
go there.

Also, it's important to have an ability to wait on a thread's exit. If
you have other threads looking at your thread object asking to be
awoken, how do you do that ?

This code shows how I did it, it works well...
http://www.google.com/codesearch?hl=...hread_cpp.i#a0

Take a look at TaskContext::start_routine

It is the responsibility of other threads to delete the thread object.

The austria c++ stuff is made such that no system headers are needed in
application code and it is implemented for win32 and posix.

For a topcoder app, I used the austria C++ api but I ripped out the
layer that hit pthreads. It should be easier to tell what's going on here.

http://www.topcoder.com/longcontest/...08764&subnum=4

#include <pthread.h>

namespace tc
{
// All the posix thread stuff goes here - API conforms to Austria C++

// ======== MutexAttr =================================================
class MutexAttr
{
public:

MutexAttr( int i_kind )
{
pthread_mutexattr_init( m_attr );
if ( pthread_mutexattr_settype( m_attr, i_kind ) != 0 )
{
abort();
}
}

~MutexAttr()
{
pthread_mutexattr_destroy( m_attr );
}

pthread_mutexattr_t * GetAttr()
{
return m_attr;
}

pthread_mutexattr_t m_attr[ 1 ];

};

MutexAttr g_MA_Fast( PTHREAD_MUTEX_FAST_NP );
MutexAttr g_MA_Recursive( PTHREAD_MUTEX_RECURSIVE_NP );
MutexAttr g_MA_Check( PTHREAD_MUTEX_ERRORCHECK_NP );

// ======== Mutex ================================================== ===

class Conditional;
class Mutex
{

public:
friend class Conditional;

// ======== MutexType =============================================

enum MutexType
{
NonRecursive,

Recursive,

Checking
};
// ======== Mutex =================================================

Mutex( MutexType i_type = NonRecursive )
{
pthread_mutex_t * l_mutex = m_mutex_context.m_data;

switch ( i_type )
{
case NonRecursive :
{
int l_result = pthread_mutex_init( l_mutex,
g_MA_Fast.GetAttr() );

if ( l_result != 0 )
{
abort();
}

break;
}
case Recursive :
{
int l_result = pthread_mutex_init( l_mutex,
g_MA_Recursive.GetAttr() );

if ( l_result != 0 )
{
abort();
}

break;
}
case Checking :
{
int l_result = pthread_mutex_init( l_mutex,
g_MA_Check.GetAttr() );

if ( l_result != 0 )
{
abort();
}

break;
}
default :
{
abort();
}
}
}

// ======== Mutex =================================================

virtual ~Mutex()
{
pthread_mutex_t * l_mutex = m_mutex_context.m_data;

int l_result = pthread_mutex_destroy( l_mutex );

if ( l_result != 0 )
{
// trying to destroy a mutex that is locked
abort();
}
}
// ======== Lock ==================================================

void Lock()
{
pthread_mutex_t * l_mutex = m_mutex_context.m_data;

int l_result = pthread_mutex_lock( l_mutex );

if ( l_result != 0 )
{
if ( l_result == EINVAL )
{
abort();
}

if ( l_result == EDEADLK )
{
abort();
}

abort();
}
}
// ======== TryLock ===============================================

bool TryLock()
{
pthread_mutex_t * l_mutex = m_mutex_context.m_data;

int l_result = pthread_mutex_trylock( l_mutex );

if ( EBUSY == l_result )
{
return false;
}

if ( l_result != 0 )
{
if ( l_result == EINVAL )
{
abort();
}

abort();
}

return true;
}
// ======== Unlock ================================================

void Unlock()
{
pthread_mutex_t * l_mutex = m_mutex_context.m_data;

int l_result = pthread_mutex_unlock( l_mutex );

if ( l_result != 0 )
{
if ( l_result == EINVAL )
{
abort();
}

if ( l_result == EPERM )
{
abort();
}

abort();
}
}

struct MutexContext
{
pthread_mutex_t m_data[1];
};

private:

/**
* m_mutex_context is a system dependant context variable.
*/

MutexContext m_mutex_context;

// copy constructor and assignment operator are private and
// unimplemented. It is illegal to copy a mutex.
Mutex( const Mutex & );
Mutex & operator= ( const Mutex & );
};

// ======== Conditional ===============================================
// condition variable wrapper

class Conditional
{
public:

// ======== Conditional ===========================================

Conditional( Mutex & i_mutex )
: m_mutex( i_mutex.m_mutex_context.m_data )
{
int l_result = pthread_cond_init(
m_cond,
static_cast<const pthread_condattr_t *>( 0 )
);

if ( l_result != 0 )
{
abort();
}

}

// destructor
virtual ~Conditional()
{
int l_result = pthread_cond_destroy(
m_cond
);

if ( l_result != 0 )
{
abort();
}
}

// ======== Wait ==================================================
void Wait()
{
int l_result = pthread_cond_wait( m_cond, m_mutex );

if ( l_result != 0 )
{
abort();
}
}

// ======== Post ==================================================
void Post()
{
int l_result = pthread_cond_signal( m_cond );

if ( l_result != 0 )
{
abort();
}
}
// ======== PostAll ===============================================
void PostAll()
{
int l_result = pthread_cond_broadcast( m_cond );

if ( l_result != 0 )
{
abort();
}
}
private:

pthread_mutex_t * m_mutex;
pthread_cond_t m_cond[ 1 ];

// copy constructor and assignment operator are private and
// unimplemented. It is illegal to copy a Conditional.
Conditional( const Conditional & );
Conditional & operator= ( const Conditional & );

};

// ======== ConditionalMutex ==========================================

class ConditionalMutex
: public Mutex,
public Conditional
{
public:
// ======== ConditionalMutex ======================================

ConditionalMutex( MutexType i_type = NonRecursive )
: Mutex( i_type ),
Conditional( * static_cast< Mutex * >( this ) )
{
}
virtual ~ConditionalMutex() {}

private:
ConditionalMutex( const ConditionalMutex & );
ConditionalMutex & operator= ( const ConditionalMutex & );
};
// ======== Lock ================================================

template <typename w_MutexType>
class Lock
{
public:

w_MutexType & m_mutex;

Lock( w_MutexType & io_mutex )
: m_mutex( io_mutex )
{
m_mutex.Lock();
}

~Lock()
{
m_mutex.Unlock();
}

void Wait()
{
return m_mutex.Wait();
}

void Post()
{
m_mutex.Post();
}

void PostAll()
{
m_mutex.PostAll();
}

private:

// must not allow copy or assignment so make
// these methods private.
Lock( const Lock & );
Lock & operator=( const Lock & );
};

// ======== Unlock =============================================

template <typename w_MutexType>
class Unlock
{
public:

w_MutexType & m_mutex;

Unlock( w_MutexType & io_mutex )
: m_mutex( io_mutex )
{
m_mutex.Unlock();
}

~Unlock()
{
m_mutex.Lock();
}

private:

// must not allow copy or assignment so make
// these methods private.
Unlock( const Unlock & );
Unlock & operator=( const Unlock & );
};

// ======== TryLock ================================================== =
template< typename w_MutexType >
class TryLock
{
w_MutexType & m_mutex;

bool m_is_acquired;

public:

TryLock( w_MutexType & io_mutex )
: m_mutex( io_mutex ),
m_is_acquired( false )
{

m_is_acquired = m_mutex.TryLock();
}

inline ~TryLock()
{
if ( m_is_acquired )
{
m_mutex.Unlock();
}
}

void SetAquired( bool i_is_acquired )
{
m_is_acquired = i_is_acquired;
}

bool IsAcquired() const
{
return m_is_acquired;
}

private:

/* Unimplemented. */
TryLock( const TryLock & );
TryLock & operator=( const TryLock & );

};
// ======== Task ================================================== ====

class Task
{
public:

typedef int TaskID;
// ======== Task ==================================================

Task()
: m_started( false ),
m_completed( false ),
m_is_joined( false )
{
int l_result = pthread_create(
& m_thread_id,
static_cast<const pthread_attr_t *>( 0 ),
& start_routine,
static_cast<void *>( this )
);

if ( 0 != l_result )
{
abort();
}
}

// ======== ~Task =================================================

virtual ~Task()
{
Wait();
}
// ======== Work ==================================================

virtual void Work() = 0;

// ======== Start =================================================

void Start()
{
if ( ! m_started )
{
// Wake this thread
Lock<ConditionalMutex l_lock( m_thread_cond_mutex );

m_started = true;
l_lock.Post();
}
}

// ======== Wait ==================================================

void Wait()
{
if ( ! m_is_joined )
{
// Wait here to be started
Lock<ConditionalMutex l_lock( m_wait_cond_mutex );

while ( ! m_completed )
{
l_lock.Wait();
}

// Need to call join here ...

if ( ! m_is_joined )
{
m_is_joined = true;

void * l_return_value;

int l_result = pthread_join(
m_thread_id,
& l_return_value
);

if ( 0 != l_result )
{
abort();
}
}

} // l_lock is unlocked here

}

// ======== GetThisId =============================================

TaskID GetThisId()
{
return m_thread_id;
}
// ======== GetSelfId =============================================

static TaskID GetSelfId()
{
return ::pthread_self();
}

private:

//
// Can't copy a task.
Task( const Task & );
Task & operator= ( const Task & );

pthread_t m_thread_id;

volatile bool m_started;

volatile bool m_completed;

volatile bool m_is_joined;

ConditionalMutex m_thread_cond_mutex;

ConditionalMutex m_wait_cond_mutex;
static void * start_routine( void * i_task )
{
Task * l_this_task = static_cast<Task *>( i_task );

{
// Wait here to be started
Lock<ConditionalMutex l_lock(
l_this_task->m_thread_cond_mutex );

while ( ! l_this_task->m_started )
{
l_lock.Wait();
}
}

// do the work ...
l_this_task->Work();

{
// Wake all the waiters.
Lock<ConditionalMutex l_lock(
l_this_task->m_wait_cond_mutex );

l_this_task->m_completed = true;
l_lock.PostAll();
}

return 0;
}
};
// ======== Barrier ================================================== =

class Barrier
{
public:

Barrier(
unsigned i_thread_count,
ConditionalMutex & i_cond_mutex
)
: m_thread_count( i_thread_count ),
m_cond_mutex( i_cond_mutex ),
m_count()
{
}

unsigned Enter()
{
unsigned l_num;
Lock<ConditionalMutex l_lock( m_cond_mutex );
l_num = m_count ++;

if ( ( m_thread_count - 1 ) == l_num )
{
l_lock.PostAll();
}
else
{
l_lock.Wait();
}
return l_num;
}

unsigned m_thread_count;
ConditionalMutex & m_cond_mutex;
volatile unsigned m_count;
};

} // namespace tc
Apr 10 '07 #4
On Apr 10, 10:31 am, "Boltar" <boltar2...@yahoo.co.ukwrote:
I'm writing a threading class using posix threads on unix with each
thread being run by an object instance. One thing I'm not sure about
is , if I do the following:
myclass::~myclass()
{
:
: do stuff
:
pthread_exit(&status);
}
If I exit the thread at the end of the destructor will all the memory
used for the object be free'd?
Maybe. C++ doesn't define threading, so it doesn't say what
would happen here, and Posix doesn't define a C++ binding, so
each implementation is on its own. In a somewhat similar (but
not precisely identical) situation, I found that Sun CC and g++
(both under Solaris) behaved differently.
My suspicion is it won't and I actually need to exit the
thread outside of the object itself, but I thought I'd check
on here first.
I'd forget about pthread_cancel and pthread_exit within C++.
Make other arrangements, throwing an exception when you want to
terminate. Catch the exception in the `extern "C"' function you
used to start the thread, and go on from there.

It's also not too clear to me what kind of a class could want to
do an exit in its destructor. pthread_exit has semantics more
or less like throwing an exception, and that's generally
something you want to avoid in a destructor. Please explain
what you're trying to do.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Apr 10 '07 #5

James Kanze wrote:
On Apr 10, 10:31 am, "Boltar" <boltar2...@yahoo.co.ukwrote:
I'm writing a threading class using posix threads on unix with each
thread being run by an object instance. One thing I'm not sure about
is , if I do the following:
myclass::~myclass()
{
:
: do stuff
:
pthread_exit(&status);
}
If I exit the thread at the end of the destructor will all the memory
used for the object be free'd?
I wasn't 100% on what you were trying to do... but was this close?

#ifndef Thread_H
#define Thread_H

#define _REENTRANT

class Thread
{
pthread_t thread;
static void * dispatch(void *);

protected:
virtual void run() = 0;
public:
virtual ~Thread(){}
void start();
void join();
};

#endif

..cpp file
-------------------------
#include "Thread.h"

void * Thread::dispatch(void * ptr)
{
if (!ptr)
return 0;

static_cast<Thread *>(ptr)->run();
pthread_exit(ptr);

return 0;
}

void Thread::start()
{
pthread_create(&thread, 0, Thread::dispatch, this);
}

void Thread::join()
{
pthread_join(thread, (void **) 0);
}

This is an ABC, as you can see the derived class must implement a
run() function... When you derived from this, you will call the
start() method wich will create the pthread.. .the creation will
callback the start() function which will execute the derived classes
run(). after run() finishes, pthread_exit() will be called to clean up
the memory.

Apr 10 '07 #6
On Apr 10, 4:49 pm, "James Kanze" <james.ka...@gmail.comwrote:
It's also not too clear to me what kind of a class could want to
do an exit in its destructor. pthread_exit has semantics more
or less like throwing an exception, and that's generally
something you want to avoid in a destructor. Please explain
what you're trying to do.
Its a TCP server. Each incoming connection gets its own thread which
is encapsulated in a connection object. I would have just used fork()
but I want the threads to access some global stats and I couldn't be
bothered with the hassle of shared memory and associated locking
issues. When the session is over or the remote client closes the
connection the thread has to exit and the object be destroyed. However
going by my own tests and whats been written here I've now just
created a procedural function which the object calls which deletes the
calling object then exits the thread.

In reponse to another post , I don't need to do a join on an exiting
thread because they're all running detached. The parent thread doesn't
need to care about them , its just a fire and forget dispatcher.

B2003

Apr 10 '07 #7
Boltar wrote:
On Apr 10, 4:49 pm, "James Kanze" <james.ka...@gmail.comwrote:
>>It's also not too clear to me what kind of a class could want to
do an exit in its destructor. pthread_exit has semantics more
or less like throwing an exception, and that's generally
something you want to avoid in a destructor. Please explain
what you're trying to do.


Its a TCP server. Each incoming connection gets its own thread which
is encapsulated in a connection object. I would have just used fork()
but I want the threads to access some global stats and I couldn't be
bothered with the hassle of shared memory and associated locking
issues.
You will still have "locking" issues wether you use shared memory or
threads (where memory is implicitly shared).
... When the session is over or the remote client closes the
connection the thread has to exit and the object be destroyed.
Considered using a thread pool?
... However
going by my own tests and whats been written here I've now just
created a procedural function which the object calls which deletes the
calling object then exits the thread.

In reponse to another post , I don't need to do a join on an exiting
thread because they're all running detached. The parent thread doesn't
need to care about them , its just a fire and forget dispatcher.
That's true until you try to exit. The main thread must wait until all
threads have cleaned up before it exits. You will have strange
behaviour if you don't.
Apr 10 '07 #8
On Apr 10, 11:00 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Boltar wrote:
On Apr 10, 4:49 pm, "James Kanze" <james.ka...@gmail.comwrote:
>It's also not too clear to me what kind of a class could want to
do an exit in its destructor. pthread_exit has semantics more
or less like throwing an exception, and that's generally
something you want to avoid in a destructor. Please explain
what you're trying to do.
Its a TCP server. Each incoming connection gets its own thread which
is encapsulated in a connection object. I would have just used fork()
but I want the threads to access some global stats and I couldn't be
bothered with the hassle of shared memory and associated locking
issues.

You will still have "locking" issues wether you use shared memory or
threads (where memory is implicitly shared).
True, but with threads you can use mutexes. You can't do that with
seperate processes (and despite what some people think you can't map
mutexes to shared memory since if the underlying mutex code uses
pointers you're screwed). For processes you have to use SysV
semaphores (yuck) or a locking file (yuck again).
>
... When the session is over or the remote client closes the
connection the thread has to exit and the object be destroyed.

Considered using a thread pool?
Can't be bothered :) Its not a high throughput server, the overhead of
creating/destroying threads to keep the code simple is worth it.
That's true until you try to exit. The main thread must wait until all
threads have cleaned up before it exits. You will have strange
behaviour if you don't.
If the parent thread ever exits other than via a crash it'll cause an
entire process halt so thats not an issue.

B2003
Apr 11 '07 #9
Boltar wrote:
On Apr 10, 11:00 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
>>Boltar wrote:
>>>On Apr 10, 4:49 pm, "James Kanze" <james.ka...@gmail.comwrote:
>>>>It's also not too clear to me what kind of a class could want to
do an exit in its destructor. pthread_exit has semantics more
or less like throwing an exception, and that's generally
something you want to avoid in a destructor. Please explain
what you're trying to do.
>>>Its a TCP server. Each incoming connection gets its own thread which
is encapsulated in a connection object. I would have just used fork()
but I want the threads to access some global stats and I couldn't be
bothered with the hassle of shared memory and associated locking
issues.

You will still have "locking" issues wether you use shared memory or
threads (where memory is implicitly shared).


True, but with threads you can use mutexes. You can't do that with
seperate processes (and despite what some people think you can't map
mutexes to shared memory since if the underlying mutex code uses
pointers you're screwed). For processes you have to use SysV
semaphores (yuck) or a locking file (yuck again).
<OT>Decent operating systems support process shared mutex and you can
put them in shared memory.</OT>

--
Ian Collins.
Apr 11 '07 #10
On Apr 11, 9:55 am, Ian Collins <ian-n...@hotmail.comwrote:
<OT>Decent operating systems support process shared mutex and you can
put them in shared memory.</OT>
Maybe , maybe not. Would you be willing to be portability on it always
working?

B2003

Apr 11 '07 #11
On Apr 10, 6:17 pm, "bjeremy" <bjer...@sbcglobal.netwrote:

[...]
#ifndef Thread_H
#define Thread_H
#define _REENTRANT
class Thread
{
pthread_t thread;
static void * dispatch(void *);
protected:
virtual void run() = 0;
public:
virtual ~Thread(){}
void start();
void join();
};
#endif
.cpp file
-------------------------
#include "Thread.h"
void * Thread::dispatch(void * ptr)
{
if (!ptr)
return 0;
static_cast<Thread *>(ptr)->run();
pthread_exit(ptr);
You don't need to call pthread_exit here---in fact, in many
cases, you don't want to (since calling pthread_exit will, at
least in some implementations, prevent the destructors of local
variables from running). Just return. (Actually, you don't
want to ever call pthread_exit if you're using C++, because
implementations---even different compilers on the same
platform---don't seem to agree as to what it should do.)
return 0;
}
void Thread::start()
{
pthread_create(&thread, 0, Thread::dispatch, this);
Attention! This shouldn't compile (although g++ has a bug, and
doesn't detect the error). The type of function required by
pthread_create is `extern "C"', and a member function, even
static, can never be `extern "C"'.
}
void Thread::join()
{
pthread_join(thread, (void **) 0);
}
This is an ABC, as you can see the derived class must implement a
run() function... When you derived from this, you will call the
start() method wich will create the pthread.. .the creation will
callback the start() function which will execute the derived classes
run(). after run() finishes, pthread_exit() will be called to clean up
the memory.
What relationship to his question?

He was talking about calling pthread_exit in a destructor, which
makes me think that he probably had detached threads in mind.
For detached threads, I don't use a class at all; just a
(template) function, which takes a functional object (or a
pointer to function) as parameter.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 11 '07 #12
On Apr 10, 11:47 pm, "Boltar" <boltar2...@yahoo.co.ukwrote:
On Apr 10, 4:49 pm, "James Kanze" <james.ka...@gmail.comwrote:
It's also not too clear to me what kind of a class could want to
do an exit in its destructor. pthread_exit has semantics more
or less like throwing an exception, and that's generally
something you want to avoid in a destructor. Please explain
what you're trying to do.
Its a TCP server. Each incoming connection gets its own thread which
is encapsulated in a connection object. I would have just used fork()
but I want the threads to access some global stats and I couldn't be
bothered with the hassle of shared memory and associated locking
issues. When the session is over or the remote client closes the
connection the thread has to exit and the object be destroyed. However
going by my own tests and whats been written here I've now just
created a procedural function which the object calls which deletes the
calling object then exits the thread.
Yes. You need the procedural function anyway, to start the
thread. You might as well delete the object there.

My real question concerning your initial design, I guess, was
who was going to call the destructor. A thread is a function,
an asynchronous function, but a function.
In reponse to another post , I don't need to do a join on an exiting
thread because they're all running detached. The parent thread doesn't
need to care about them , its just a fire and forget dispatcher.
And of course, you never stop the server, so there's no worry
about calling exit with running threads (which can cause various
problems as well):-). If not, for a clean shutdown (especially
given that pthread_cancel doesn't work in C++), you need a
thread counter, and a flag which signals that shutdown is
requested, which the threads poll from time to time. The flag
must be protected by a mutex, and the thread counter by a
condition variable (since it will be decremented at the end of
the procedural function, just before the return). Set the flag,
and wait until the counter is 0, then return from main.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 11 '07 #13
On Apr 11, 10:38 am, "Boltar" <boltar2...@yahoo.co.ukwrote:
On Apr 10, 11:00 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
Boltar wrote:
On Apr 10, 4:49 pm, "James Kanze" <james.ka...@gmail.comwrote:
>>It's also not too clear to me what kind of a class could want to
>>do an exit in its destructor. pthread_exit has semantics more
>>or less like throwing an exception, and that's generally
>>something you want to avoid in a destructor. Please explain
>>what you're trying to do.
Its a TCP server. Each incoming connection gets its own thread which
is encapsulated in a connection object. I would have just used fork()
but I want the threads to access some global stats and I couldn't be
bothered with the hassle of shared memory and associated locking
issues.
You will still have "locking" issues wether you use shared memory or
threads (where memory is implicitly shared).
True, but with threads you can use mutexes. You can't do that with
seperate processes (and despite what some people think you can't map
mutexes to shared memory since if the underlying mutex code uses
pointers you're screwed).
Some people, in this case, being the authors of the Posix
standard. See pthread_mutexattr_setpshared() in the standard,
for example. Note that this functionality is optional---as is
threading, for that matter. From personal experience, it is
present under Solaris and Linux, however, and I would expect it
to be fairly widespread.

I've used it under Solaris with no problem, with the mutex
itself in a mmap'ed file mapped into and shared between two
processes.

It's also true that the Posix standard (and the rationale) speak
of allocating memory on the heap, etc. in pthread_mutex_lock. I
suspect that this could only be made to work if thread
process-shared synchronization was not supported; at any rate,
it's the system's problem to make it work, not yours.
For processes you have to use SysV
semaphores (yuck) or a locking file (yuck again).
You have to have some memory which is common to the processes
involved. This can be shared memory, but I've found that
typically, mmap'ing is easier and works better.
... When the session is over or the remote client closes the
connection the thread has to exit and the object be destroyed.
Considered using a thread pool?
Can't be bothered :) Its not a high throughput server, the overhead of
creating/destroying threads to keep the code simple is worth it.
Yes. It's the sort of thing that if you already have the
existing code, why not, but it's not worth the hassle to develop
it new.
That's true until you try to exit. The main thread must wait until all
threads have cleaned up before it exits. You will have strange
behaviour if you don't.
If the parent thread ever exits other than via a crash it'll cause an
entire process halt so thats not an issue.
There's a lot that happens between the moment the parent thread
calls exit, and the moment the process actually stops running.
If other threads are running during that time, or at least if
they're doing anything non-trivial, you can sometimes get
surprising results. It's not too difficult keep count of your
threads, set a global flag for a clean shutdown, and wait until
the count is 0.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 11 '07 #14
Boltar wrote:
On Apr 10, 11:00 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
....
>
True, but with threads you can use mutexes. You can't do that with
seperate processes (and despite what some people think you can't map
mutexes to shared memory since if the underlying mutex code uses
pointers you're screwed). For processes you have to use SysV
semaphores (yuck) or a locking file (yuck again).
Wimp - implement your own mutex using relative pointers if you have to.
>
>>>... When the session is over or the remote client closes the
connection the thread has to exit and the object be destroyed.

Considered using a thread pool?


Can't be bothered :) Its not a high throughput server, the overhead of
creating/destroying threads to keep the code simple is worth it.
I find that once you have a nice threadpool library, it can make life
much simpler and you can do a few things that you really can't do if the
thread was going to exit. i.e. A thread object can't really delete
itself while a threadpool hook can quite happily delete itself.
>
>>That's true until you try to exit. The main thread must wait until all
threads have cleaned up before it exits. You will have strange
behaviour if you don't.


If the parent thread ever exits other than via a crash it'll cause an
entire process halt so thats not an issue.
That would make it not a very modular system. This would make it
difficult to test and testability should be a primary deliverable to any
quality code.
Apr 11 '07 #15
James Kanze wrote:
....
>
Yes. You need the procedural function anyway, to start the
thread. You might as well delete the object there.
That won't work all the time. A clean shutdown requires that the main
thread be kept alive until after all other threads have reliably
terminated. This means (possibly other meanings too) that every thread
object must be deleted by a thread other than the thread itself before
exit from main. Creating a system that does otherwise will have you
searching for the elusive bug - I've been there too often - random
segv's on exit or shutdown of a threaded object.
>
My real question concerning your initial design, I guess, was
who was going to call the destructor. A thread is a function,
an asynchronous function, but a function.
A thread is a thread. Multiple threads may execute the same function at
the same time.
>
>>In reponse to another post , I don't need to do a join on an exiting
thread because they're all running detached. The parent thread doesn't
need to care about them , its just a fire and forget dispatcher.


And of course, you never stop the server, so there's no worry
about calling exit with running threads (which can cause various
problems as well):-). If not, for a clean shutdown (especially
given that pthread_cancel doesn't work in C++), you need a
thread counter, and a flag which signals that shutdown is
requested, which the threads poll from time to time. The flag
must be protected by a mutex, and the thread counter by a
condition variable (since it will be decremented at the end of
the procedural function, just before the return). Set the flag,
and wait until the counter is 0, then return from main.
Right - somthing like that ...
Apr 11 '07 #16
You don't need to call pthread_exit here---in fact, in many
cases, you don't want to (since calling pthread_exit will, at
least in some implementations, prevent the destructors of local
Yeah.. actually I re-read the specs, it said that there is an
implicit pthread_exit when the function that was passed into
pthread_create, returns... so I guess you are right, it was not needed
>
void Thread::start()
{
pthread_create(&thread, 0, Thread::dispatch, this);

Attention! This shouldn't compile (although g++ has a bug, and
doesn't detect the error). The type of function required by
pthread_create is `extern "C"', and a member function, even
static, can never be `extern "C"'.
Actually.. I haven't run it on a compiler that won't accept this..
MSVC, g++, gcc.. all seem fine with it... but I'll double check the
specs on this... I didn't see anything offhand that says I can not use
a static member... but if you can point me too a specific reference
that would be cool...
>
What relationship to his question?

He was talking about calling pthread_exit in a destructor, which
makes me think that he probably had detached threads in mind.
For detached threads, I don't use a class at all; just a
(template) function, which takes a functional object (or a
pointer to function) as parameter.
Yeah... I thought I covered that by starting off saying I wasn't 100%
on what he was trying to do... This was supposed to be a thread class
without having to use pthread_exit in the destructor... in order to
avoid the issue altogether...

Now.. if the OP is creating a TCP server, and its not a multi-core or
dual processor machine... I wouldn't use threads at all... its a
waste, multiplexing is much faster on a single processor... If it is
multi-core, the previous recommendation of the thread pool would
probably be the better design and also lets you sidestep the whole
issue of the thread destructor.

Apr 11 '07 #17
On Apr 11, 6:39 pm, "bjeremy" <bjer...@sbcglobal.netwrote:
Now.. if the OP is creating a TCP server, and its not a multi-core or
dual processor machine... I wouldn't use threads at all... its a
waste, multiplexing is much faster on a single processor... If it is
multi-core, the previous recommendation of the thread pool would
probably be the better design and also lets you sidestep the whole
issue of the thread destructor.
I would have multiplexed , but each connection will be sending lots of
data and I waws concerned about write blocks. Just because the
select() mask flag says the socket is ready to write doesn't mean
it'll accept everything you throw. With multiplexing every socket
would have to be non blocking so a blocked socket doesn't hang every
other session and I'd have to keep tabs of retries etc. With threads
I can just let a socket happily block and it won't affect anything
else.

B2003
Apr 12 '07 #18
On Apr 11, 7:39 pm, "bjeremy" <bjer...@sbcglobal.netwrote:
void Thread::start()
{
pthread_create(&thread, 0, Thread::dispatch, this);
Attention! This shouldn't compile (although g++ has a bug, and
doesn't detect the error). The type of function required by
pthread_create is `extern "C"', and a member function, even
static, can never be `extern "C"'.
Actually.. I haven't run it on a compiler that won't accept this..
MSVC, g++, gcc.. all seem fine with it...
I've not tried with VC++, but I know that this is a bug in g++.
Sun CC complains.
but I'll double check the
specs on this... I didn't see anything offhand that says I can not use
a static member... but if you can point me too a specific reference
that would be cool...
Well, technically, of course, it depends on the declaration of
pthread_create, and an implementation could overload it to take
either (knowing that behind the scenes there is no difference),
much in the same way the standard *requires* the library to
overload functions from the C library, like atexit, sort and
bsearch, which take pointers to functions. Neither Linux nor
Solaris do this, however, so it is probably best not to count on
it, and to just suppose that there is a single pthread_create,
declared:
extern "C" {
extern int pthread_create( pthread_t*, pthread_attr_t*,
void *(*)( void* ),
void* ) ;
}

Which means that the type of the third argument is `extern "C"
void* (*)( void* )'; only a function with "C" language linkage
can be used. (Note the end of §7.5/1: "Two function types with
different language linkages are distinct types even if they are
otherwise identical.") Finally, the last normative sentence in
§7.5/4 says "A C language linkage is ignored for the names of
class members and the member function type of class member
functions", so that even if you try to declare the static member
function to have "C" linkage, it is ignored. (I don't know the
reason for this last rule; it would make sense to allow static
member functions to have C linkage.)

[...]
Now.. if the OP is creating a TCP server, and its not a multi-core or
dual processor machine... I wouldn't use threads at all... its a
waste, multiplexing is much faster on a single processor...
Not necessarily. And multiple threads won't necessarily be
faster on a multi-core, here, since there is almost no CPU
involved anyway; it's all IO.
If it is
multi-core, the previous recommendation of the thread pool would
probably be the better design and also lets you sidestep the whole
issue of the thread destructor.
If you have the code for a thread pool handy, by all means use
it. Otherwise, I doubt that it's worth the effort necessary to
develop it.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 12 '07 #19
On Apr 11, 3:58 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
James Kanze wrote:

...
Yes. You need the procedural function anyway, to start the
thread. You might as well delete the object there.
That won't work all the time. A clean shutdown requires that the main
thread be kept alive until after all other threads have reliably
terminated.
That's a separate issue. (In some cases, there's no need for a
clean shutdown anyway. A shutdown is, by definition, unclean.)
This means (possibly other meanings too) that every thread
object must be deleted by a thread other than the thread itself before
exit from main.
I think you're confusing the "thread" object with what the OS
considers a thread. In fact, the "thread" object, here, is just
a functional object which is called by the function whose
address is passed to pthread_create. The OS knows nothing about
it, and there's not the slightest problem with deleting it in
any thread you chose, as long as you are sure that no other
thread will use it. (In every case where I've used this idiom,
no other thread has even had a pointer to this object, so no
other thread could use it.)
Creating a system that does otherwise will have you searching
for the elusive bug - I've been there too often - random
segv's on exit or shutdown of a threaded object.
Exit is a special case, and needs to be handled, but it has no
relevance here.
My real question concerning your initial design, I guess, was
who was going to call the destructor. A thread is a function,
an asynchronous function, but a function.
A thread is a thread. Multiple threads may execute the same
function at the same time.
I was using the term a bit loosely, but for the user, a thread
is the equivalent of a function called asynchronously, with its
own stack. Obviously, many threads can execute the same
function, just as, within a single threaded environment, the
same function can be executing many times simultaneously.

In at least one of the models being considered for
standardization, a thread IS an asynchronous function (which
possibly returns a type which can be used to get its return
value later).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 12 '07 #20
James Kanze wrote:
On Apr 11, 3:58 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
>>James Kanze wrote:
....
>
That's a separate issue. (In some cases, there's no need for a
clean shutdown anyway. A shutdown is, by definition, unclean.)
The C++ does describe how a shutdown works. How is it unclean ?
>
>>This means (possibly other meanings too) that every thread
object must be deleted by a thread other than the thread itself before
exit from main.


I think you're confusing the "thread" object with what the OS
considers a thread. In fact, the "thread" object, here, is just
a functional object which is called by the function whose
address is passed to pthread_create. The OS knows nothing about
it, and there's not the slightest problem with deleting it in
any thread you chose, as long as you are sure that no other
thread will use it. (In every case where I've used this idiom,
no other thread has even had a pointer to this object, so no
other thread could use it.)
I think I know what I meant. I have developed many heavily threaded
applications with C++ and my experience is that if you don't look after
shutting down, you will run into issues. The nastiest and most
difficult to debug is when you get an exception and the debugger points
to an empty page of memory. This usually happends when a thread is
executing some library code and some destructor is unloading a library
out from underneath another thread. While not impossible to debug, it
takes alot of repeated attempts to find which thread it is. Invariably,
the solution is to wait for the thread to complete before shutting down.

>
>>Creating a system that does otherwise will have you searching
for the elusive bug - I've been there too often - random
segv's on exit or shutdown of a threaded object.


Exit is a special case, and needs to be handled, but it has no
relevance here.
Special in what way ? Like strcpy does not check for the size of the
destination or sprintf buffer overruns are not important until you find
that 2/3 of the computers on the net are bots ?
>
....
In at least one of the models being considered for
standardization, a thread IS an asynchronous function (which
possibly returns a type which can be used to get its return
value later).
I assume you mean the "future" interfaces ? It's of limited value IMHO.
It can't be used to implement most of the applications I have
implemented. There was a project where we did try to use it a few years
ago and I think it didn't prove a rich enough interface.
Apr 12 '07 #21
On Apr 12, 3:32 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
James Kanze wrote:
On Apr 11, 3:58 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
>James Kanze wrote:
...
That's a separate issue. (In some cases, there's no need for a
clean shutdown anyway. A shutdown is, by definition, unclean.)
The C++ does describe how a shutdown works. How is it unclean ?
I expressed myself poorly. What I meant is that many
applications are meant to run "forever", and that the fact that
they are not (they are shutting down) means that something wrong
("unclean") has occurred.

I'm generally sceptical of this attitude, and prefer to provide
a mechanism for a clean shutdown even in programs designed to
run forever, but I've seen a lot of servers which can only be
stopped by "kill -9", or something similar.

(And of course, C++ doesn't really describe how shutdown works
in every case. It partially describes what happens if you call
exit() in a single threaded program, but it doesn't say
anything---yet---about threads, nor about what happens if the
process is the target of a "kill -9".)
>This means (possibly other meanings too) that every thread
object must be deleted by a thread other than the thread itself before
exit from main.
I think you're confusing the "thread" object with what the OS
considers a thread. In fact, the "thread" object, here, is just
a functional object which is called by the function whose
address is passed to pthread_create. The OS knows nothing about
it, and there's not the slightest problem with deleting it in
any thread you chose, as long as you are sure that no other
thread will use it. (In every case where I've used this idiom,
no other thread has even had a pointer to this object, so no
other thread could use it.)
I think I know what I meant.
Then why did you say something else?
I have developed many heavily threaded
applications with C++ and my experience is that if you don't look after
shutting down, you will run into issues.
If you provide a clean shutdown. If you don't provide a clean
shutdown, and require a "kill -9" to stop the process, then you
don't run into those issues. (You may run into others; it all
depends on what you are doing.)
The nastiest and most
difficult to debug is when you get an exception and the debugger points
to an empty page of memory.
This usually happends when a thread is
executing some library code and some destructor is unloading a library
out from underneath another thread.
That's really independant of shutdown, I'd say. Pull the rug
out from under a thread, and you're going to have problems.
Destructing an object in one thread that another thread is using
isn't a good idea, regardless of where it happens.
While not impossible to debug, it
takes alot of repeated attempts to find which thread it is. Invariably,
the solution is to wait for the thread to complete before shutting down.
No disagreement, really, but that has nothing to do with the
discussion at hand, and wasn't what you said before. In fact,
destructing the thread object in the thread, and not from
another thread, is probably the surest way of ensuring that the
object isn't destructed while the thread is still using it.
>Creating a system that does otherwise will have you searching
for the elusive bug - I've been there too often - random
segv's on exit or shutdown of a threaded object.
Exit is a special case, and needs to be handled, but it has no
relevance here.
Special in what way ?
In that you don't expect to continue running, or handling
further requests, once it has been called. In that it will
never be called in a lot of servers.
Like strcpy does not check for the size of the
destination or sprintf buffer overruns are not important until you find
that 2/3 of the computers on the net are bots ?
...
In at least one of the models being considered for
standardization, a thread IS an asynchronous function (which
possibly returns a type which can be used to get its return
value later).
I assume you mean the "future" interfaces ?
Yes.
It's of limited value IMHO.
It depends on what you are using threads for. For my
applications, it's not very useful, no. In fact, my threads are
normally detached; they correspond more to a void function which
executes asynchronously.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 13 '07 #22
James Kanze wrote:
On Apr 12, 3:32 pm, Gianni Mariani <gi3nos...@mariani.wswrote:
....
>
>>I assume you mean the "future" interfaces ?


Yes.

>>It's of limited value IMHO.


It depends on what you are using threads for. For my
applications, it's not very useful, no. In fact, my threads are
normally detached; they correspond more to a void function which
executes asynchronously.
Invariably I find myself needing many of these "things" in one process
space for various reasons ranging from stress tests to scaling. The so
called short cuts to not design a consistant shutdown cause more
problems than it's worth. Server designs that appear like simple
classes so the objects can be created and destroyed at whim make for
very stable systems and easily embeddable in all kinds of ways. It's
kind of hard to kill -9 the object.
Apr 13 '07 #23

Boltar wrote:
I would have multiplexed , but each connection will be sending lots of
data and I waws concerned about write blocks. Just because the
select() mask flag says the socket is ready to write doesn't mean
it'll accept everything you throw. With multiplexing every socket
would have to be non blocking so a blocked socket doesn't hang every
other session and I'd have to keep tabs of retries etc. With threads
I can just let a socket happily block and it won't affect anything
else.
On a single processor, with using multiple threads to handle your
connections, the effect is a lot of context switching. And using
blocking I/O (opposed to non-blocking io) is also another unecessay
bottleneck that would slow down you server. If your design allows for
it, you may want to use seperate send and receive sockets... but I
understand that not every design can do this, depending on your
application.. With sends, you would just send the data, and if you
catch a signal, just re-try the send.. don't even bother keeping track
of re-tries.
Anyway, I don't have the books in front of me at the moment, but
Stevens, "Unix Network Programming vol 1", talks about different
server types and their pros and cons... also there is a good
discussion about performance of different server tyoes in this
O'reilly book "Java Network Programming"

Apr 13 '07 #24

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Olivier Parisy | last post by:
Hi, I like to use thread to simplify the handling of independant, blocking tasks. But controling them from a main thread is not always easy to do in a clean way. So I've written some generic...
3
by: Heiko Neuhaus | last post by:
Hello all, i am Cygwin to create a simple server application. Everything seems to work fine but when i use the process manager i can see that my app is leaking handles. If i run it under native...
5
by: Tim Clacy | last post by:
When exiting function scope, which occurs first: a) destruction of local objects b) copy of value for return From disassembly of a debug target, it looks like the return value is copied before...
2
by: raxitsheth | last post by:
Hello All... I am using Posix Thread. class Parent { public: virtual void* func(void *)=0;
39
by: vineoff | last post by:
If I'm having nested loops like: for (...) for (..) for (...) { /* exit here */ } and I need to exit from there ^ . Is it better to use exceptions or goto or some other method?
3
by: Keyee Hsu | last post by:
Hi, I have a C# app that creates an AppDomain, enters it, and spawns an asyn thread to do some work and then block itself. Upon the completion of the work, the async thread supposedly terminates,...
14
by: Daisy | last post by:
From this page: http://www.c-sharpcorner.com/2/mt_beginner1.asp Thread class's Abort method is called to kill a thread permanently. Make sure you call IsAlive before Abort. if (...
5
by: care02 | last post by:
Hi! I have the following problem: I have written a short Python server that creates an indefinite simulation thread that I want to kill when quitting (Ctrl-C) from Python. Googling around has...
2
by: Kemmylinns12 | last post by:
Blockchain technology has emerged as a transformative force in the business world, offering unprecedented opportunities for innovation and efficiency. While initially associated with cryptocurrencies...
0
by: Naresh1 | last post by:
What is WebLogic Admin Training? WebLogic Admin Training is a specialized program designed to equip individuals with the skills and knowledge required to effectively administer and manage Oracle...
0
by: antdb | last post by:
Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine In the overall architecture, a new "hyper-convergence" concept was proposed, which integrated multiple engines and...
1
by: Matthew3360 | last post by:
Hi there. I have been struggling to find out how to use a variable as my location in my header redirect function. Here is my code. header("Location:".$urlback); Is this the right layout the...
2
by: Matthew3360 | last post by:
Hi, I have a python app that i want to be able to get variables from a php page on my webserver. My python app is on my computer. How would I make it so the python app could use a http request to get...
0
by: AndyPSV | last post by:
HOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and on my computerHOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and...
0
by: Arjunsri | last post by:
I have a Redshift database that I need to use as an import data source. I have configured the DSN connection using the server, port, database, and credentials and received a successful connection...
0
BLUEPANDA
by: BLUEPANDA | last post by:
At BluePanda Dev, we're passionate about building high-quality software and sharing our knowledge with the community. That's why we've created a SaaS starter kit that's not only easy to use but also...
0
by: Rahul1995seven | last post by:
Introduction: In the realm of programming languages, Python has emerged as a powerhouse. With its simplicity, versatility, and robustness, Python has gained popularity among beginners and experts...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.