C++ destructors and Pthread termination

Unlike some other implementations of threads, C++ destructors for automatic objects are allowed to run in a well defined and consistent manner when a thread is terminated.

The following list includes some of the causes of thread termination:

When a thread terminates, the following occurs:

  1. If the thread was ended using pthread_exit(), pthread_cancel() or return from the thread start routine, then cancellation cleanup handlers and data destructors are run.
  2. The thread is terminated. At the time that the thread is terminated, both C++ destructors for automatic objects and i5/OS cancel handlers run.

If a Pthread is terminated using a non-Pthread method (an i5/OS exception, a different thread termination primitive provided by the system, exit() or abort(), or other job termination method), Pthread cancellation cleanup handlers and data destructors do not run.


Example

This example shows the relationship between C++ destructors and Pthread cleanup mechanisms.

See Code disclaimer information for information pertaining to code examples.

#define _MULTI_THREADED
#include <stdio.h>
#include <qp0z1170.h>
#include <time.h>
#include <pthread.h>
#include "check.h"

#define bufferSize 100
#define threadRc   55

pthread_key_t   tlskey;

void dataDestructor(void *parm);
void cancelHandler(void *parm);
void *threadfunc(void *parm);
void level2(void);
void level3(void);


class A {
public:
  A(char *label);
  ~A();
private:
  pthread_id_np_t       tid;
  char                  buffer[bufferSize];
};


void dataDestructor(void *parm) {
  printf("In data destructor\n");
  pthread_setspecific(tlskey, NULL);
}

void cancelHandler(void *parm) {
  printf("In cancellation cleanup handler\n");
}

void *threadfunc(void *parm) {
  A             object("start routine object");
  level2();
  return NULL;
}

void level2(void) {
  A             object("Second level object");
  level3();
}

void level3(void) {
  int               rc;
  struct timespec   ts = {5, 0};
  A             object("Third level object");

  pthread_setspecific(tlskey, &tlskey);
  pthread_cleanup_push(cancelHandler, NULL);
  printf("Thread blocked\n");
  rc = pthread_delay_np(&ts);
  if (rc != 0) {
    printf("pthread_delay_np() - return code %d\n", rc);
    return;
  }
  printf("Calling pthread_exit()\n");
  pthread_exit(__VOID(threadRc));
  pthread_cleanup_pop(0);
}

int main(int argc, char **argv)
{
  int                   rc=0;
  int                   i;
  pthread_t             threadid;
  void                 *status;
  int                   fail=0;

  printf("Enter Testcase - %s\n", argv[0]);
  rc = pthread_key_create(&tlskey, dataDestructor);
  checkResults("pthread_key_create()\n", rc);

  printf("----------- Start pthread_cancel() example -------------\n");
  printf("Create a thread\n");
  rc = pthread_create(&threadid, NULL, threadfunc, NULL);
  checkResults("pthread_create()\n", rc);

  sleep(2);
  rc = pthread_cancel(threadid);
  checkResults("pthread_cancel()\n", rc);

  rc = pthread_join(threadid, &status);
  checkResults("pthread_join()\n", rc);
  if (status != PTHREAD_CANCELED) {
    printf("Canceled thread did not return the expected results\n");
    fail = 1;
  }

  printf("----------- Start pthread_exit() example -------------\n");
  printf("Create a thread\n");
  rc = pthread_create(&threadid, NULL, threadfunc, NULL);
  checkResults("pthread_create()\n", rc);

  rc = pthread_join(threadid, &status);
  checkResults("pthread_join()\n", rc);
  if (__INT(status) != threadRc) {
    printf("pthread_exit() thread did not return the expected results\n");
    fail = 1;
  }

  pthread_key_delete(tlskey);
  if (fail) {
    printf("At least one thread failed!\n");
    exit(1);
  }
  printf("Main completed\n");
  return 0;
}

A::A(char *label) {
  strncpy(buffer, label, bufferSize);
  pthread_t             me;
  me = pthread_self();
  pthread_getunique_np(&me, &tid);
  printf("`%s' instantiated in thread 0x%.8x %.8x\n",
         buffer, tid);
}
A::~A() {
  printf("`%s' destroyed in thread 0x%.8x %.8x\n",
         buffer, tid);
}

Output:

Enter Testcase - QP0WTEST/TPCPP0
----------- Start pthread_cancel() example -------------
Create a thread
`start routine object' instantiated in thread 0x00000000 00000161
`Second level object' instantiated in thread 0x00000000 00000161
`Third level object' instantiated in thread 0x00000000 00000161
Thread blocked
In cancellation cleanup handler
In data destructor
`Third level object' destroyed in thread 0x00000000 00000161
`Second level object' destroyed in thread 0x00000000 00000161
`start routine object' destroyed in thread 0x00000000 00000161
----------- Start pthread_exit() example -------------
Create a thread
`start routine object' instantiated in thread 0x00000000 00000162
`Second level object' instantiated in thread 0x00000000 00000162
`Third level object' instantiated in thread 0x00000000 00000162
Thread blocked
Calling pthread_exit()
In cancellation cleanup handler
In data destructor
`Third level object' destroyed in thread 0x00000000 00000162
`Second level object' destroyed in thread 0x00000000 00000162
`start routine object' destroyed in thread 0x00000000 00000162
Main completed

Top | Pthread APIs | APIs by category