POSIX threads, thread-specific data: what about the "main" thread?

POSIX threads, thread-specific data: what about the "main" thread?

Post by Chris Ranki » Fri, 27 Oct 2000 21:18:28



Hi,

I am looking into POSIX threads and thread-specific data, and I am
unclear how pthreads treats the main thread (or expects the main thread
to be treated). For instance, it seems perfectly legal to create
thread-specific data for the main thread. However, this data's
destructor function does not seem to be called unless the main thread
explicitly exits with pthread_exit(). I would have thought that a
multi-threaded application would have executed the clean-up handlers for
ALL threads. Worse still, on some platforms, exiting the main thread via
pthread_exit() means that certain static destructors aren't called.

This is my demo code (C++):

#include <cstring>
#include <iostream>
using namespace std;

#include <unistd.h>
#include <pthread.h>

extern "C"
{
  static void cleanUp(void*);
  void* thread_function(void*);

Quote:}

class ThreadSingle
{
private:
  ThreadSingle();
  ~ThreadSingle();

  ThreadSingle(const ThreadSingle&);
  ThreadSingle& operator=(const ThreadSingle&);

  class Manager
  {
  public:
    Manager();
    ~Manager();
  };

  static pthread_key_t key;
  static Manager manager;

  friend class Manager;
  friend void cleanUp(void*);

public:
  static ThreadSingle* Instance();

Quote:};

pthread_key_t ThreadSingle::key;
ThreadSingle::Manager ThreadSingle::manager;

ThreadSingle::Manager::Manager()
{
  pthread_key_create(&key, cleanUp);
  cout << "Creating multi-threaded key: " << key << endl;

Quote:}

ThreadSingle::Manager::~Manager()
{
  /*
   * Delete any data attached to the main thread ...
   */
  void *p = pthread_getspecific(key);
  if (p) cleanUp(p);

  pthread_key_delete(key);
  cout << "Deleted multi-threaded key: " << key << endl;

Quote:}

static void
cleanUp(void *p)
{
  cout << "Calling clean-up with " << p << endl;
  delete static_cast<ThreadSingle*>(p);

Quote:}

ThreadSingle*
ThreadSingle::Instance()
{
  ThreadSingle* ptr =
static_cast<ThreadSingle*>(pthread_getspecific(key));

  if ( !ptr )
  {
    ptr = new ThreadSingle();
    pthread_setspecific(key, ptr);
  }

  cout << "- ThreadSingle at " << ptr << endl;
  return ptr;

Quote:}

ThreadSingle::ThreadSingle()
{
  cout << "Creating ThreadSingle" << endl;

Quote:}

ThreadSingle::~ThreadSingle()
{
  cout << "Destroying ThreadSingle" << endl;

Quote:}

void*
thread_function(void *p)
{
  cout << "In a thread: arg=" << p << endl;

  ThreadSingle::Instance();
  ThreadSingle::Instance();
  sleep(1);
  ThreadSingle::Instance();
  ThreadSingle::Instance();

  return p;

Quote:}

int
main()
{
  ThreadSingle::Instance();

  pthread_t id;
  if ( pthread_create(&id, NULL, thread_function,
                        reinterpret_cast<void*>(0x8080)) != 0 )
  {
    cout << "Could not create thread" << endl;
  }
  else
  {
    int ret;

    ThreadSingle::Instance();
    sleep(1);
    ThreadSingle::Instance();
    ThreadSingle::Instance();

    void *status;
    if ((ret = pthread_join(id, &status)) != 0)
    {
      cout << "Error: " << strerror(ret) << endl;
    }
    else
    {
      cout << "Thread returns: " << status << endl;
    }
  }

  return 0;

Quote:}

The point here is to make sure that any instance of the class is
destroyed whenever its thread exits, and I guess it all boils down to
whether it is legal for the main thread to call pthread_exit() or not. I
am hoping "not", because I can then safely destroy the object in the
Manager's static destructor. Note that this code also has to make
limited sense if compiled in single-threaded mode.

Can anyone advise me on this, please?
Cheers,
Chris

 
 
 

POSIX threads, thread-specific data: what about the "main" thread?

Post by Ian Collin » Sat, 28 Oct 2000 14:09:53


Without looking too deeply into the code...

The process is single threaded until pthred_create is called.  At this point
main() becomes another thread.  To exit main without exiting the
application, you have to call pthread_exit in main.

    Ian


> Hi,

> I am looking into POSIX threads and thread-specific data, and I am
> unclear how pthreads treats the main thread (or expects the main thread
> to be treated). For instance, it seems perfectly legal to create
> thread-specific data for the main thread. However, this data's
> destructor function does not seem to be called unless the main thread
> explicitly exits with pthread_exit(). I would have thought that a
> multi-threaded application would have executed the clean-up handlers for
> ALL threads. Worse still, on some platforms, exiting the main thread via
> pthread_exit() means that certain static destructors aren't called.

> This is my demo code (C++):

> #include <cstring>
> #include <iostream>
> using namespace std;

> #include <unistd.h>
> #include <pthread.h>

> extern "C"
> {
>   static void cleanUp(void*);
>   void* thread_function(void*);
> }

> class ThreadSingle
> {
> private:
>   ThreadSingle();
>   ~ThreadSingle();

>   ThreadSingle(const ThreadSingle&);
>   ThreadSingle& operator=(const ThreadSingle&);

>   class Manager
>   {
>   public:
>     Manager();
>     ~Manager();
>   };

>   static pthread_key_t key;
>   static Manager manager;

>   friend class Manager;
>   friend void cleanUp(void*);

> public:
>   static ThreadSingle* Instance();
> };

> pthread_key_t ThreadSingle::key;
> ThreadSingle::Manager ThreadSingle::manager;

> ThreadSingle::Manager::Manager()
> {
>   pthread_key_create(&key, cleanUp);
>   cout << "Creating multi-threaded key: " << key << endl;
> }

> ThreadSingle::Manager::~Manager()
> {
>   /*
>    * Delete any data attached to the main thread ...
>    */
>   void *p = pthread_getspecific(key);
>   if (p) cleanUp(p);

>   pthread_key_delete(key);
>   cout << "Deleted multi-threaded key: " << key << endl;
> }

> static void
> cleanUp(void *p)
> {
>   cout << "Calling clean-up with " << p << endl;
>   delete static_cast<ThreadSingle*>(p);
> }

> ThreadSingle*
> ThreadSingle::Instance()
> {
>   ThreadSingle* ptr =
> static_cast<ThreadSingle*>(pthread_getspecific(key));

>   if ( !ptr )
>   {
>     ptr = new ThreadSingle();
>     pthread_setspecific(key, ptr);
>   }

>   cout << "- ThreadSingle at " << ptr << endl;
>   return ptr;
> }

> ThreadSingle::ThreadSingle()
> {
>   cout << "Creating ThreadSingle" << endl;
> }

> ThreadSingle::~ThreadSingle()
> {
>   cout << "Destroying ThreadSingle" << endl;
> }

> void*
> thread_function(void *p)
> {
>   cout << "In a thread: arg=" << p << endl;

>   ThreadSingle::Instance();
>   ThreadSingle::Instance();
>   sleep(1);
>   ThreadSingle::Instance();
>   ThreadSingle::Instance();

>   return p;
> }

> int
> main()
> {
>   ThreadSingle::Instance();

>   pthread_t id;
>   if ( pthread_create(&id, NULL, thread_function,
>                         reinterpret_cast<void*>(0x8080)) != 0 )
>   {
>     cout << "Could not create thread" << endl;
>   }
>   else
>   {
>     int ret;

>     ThreadSingle::Instance();
>     sleep(1);
>     ThreadSingle::Instance();
>     ThreadSingle::Instance();

>     void *status;
>     if ((ret = pthread_join(id, &status)) != 0)
>     {
>       cout << "Error: " << strerror(ret) << endl;
>     }
>     else
>     {
>       cout << "Thread returns: " << status << endl;
>     }
>   }

>   return 0;
> }

> The point here is to make sure that any instance of the class is
> destroyed whenever its thread exits, and I guess it all boils down to
> whether it is legal for the main thread to call pthread_exit() or not. I
> am hoping "not", because I can then safely destroy the object in the
> Manager's static destructor. Note that this code also has to make
> limited sense if compiled in single-threaded mode.

> Can anyone advise me on this, please?
> Cheers,
> Chris


 
 
 

POSIX threads, thread-specific data: what about the "main" thread?

Post by Chris Ranki » Sat, 28 Oct 2000 23:43:59



> Without looking too deeply into the code...

> The process is single threaded until pthread_create is called.  At this point
> main() becomes another thread.  To exit main without exiting the
> application, you have to call pthread_exit in main.

True, but I join my second thread to my main thread again before I allow
my main thread to exit. At this point, the application becomes
single-threaded again and I still have one piece of thread-specific
storage to deallocate.

The point is that every instance of the class must be destroyed,
assuming that I don't blow the process away by calling exit() somewhere.

Chris

 
 
 

1. Thread Campers' "Threads Primer" Copy

In may 95 I attended Sun's Technology Camp on Multithread programming.
THe material for this camp was supposed to include a copy of the book
"Threads Primer", but as the book was not ready that time Sun promised
to send a copy to all the attendies later when books get ready.
Now though the book is ready for several days, I did not get my copy.
Did any one of you who attended the Camp got your copy?

Is Sun planning to ship the book to the Camp attendies in near future?

Ajay

2. Flatbed Scanner- which have a Linux driver?

3. Exception in thread "main", NoClassDefFoundError

4. SCO Oracle 7.3. - Linux iBCS - JDBC - shmget() error

5. Threads, threads, threads

6. raid device not mounting at boot

7. Threads in linux versus threads in NT and threads in Solaris.

8. help with fasttrak setup

9. threads packages: kernel threads vs. user threads

10. using posix threads ("Hello World!")

11. main thread unexpected death after killing spawned threads

12. An addition to the "Failed CGI" and "Error Log for Apache" threads