Thread creation using C++ methods as target does not work

Often, as a C++ programmer, you may want to abstract the concept of a thread into a C++ class. To do this, you must realize that the Pthread APIs are C language APIs. The Pthread APIs use functions that have C linkage and calling conventions. For your application to successfully use the pthread functions, you must provide helper functions of the appropriate type and linkage for the Pthread APIs that take function pointers as parameters.

When sharing objects between threads, always be aware of which thread is manipulating the object, which thread is responsible for freeing the object, and what thread safety issues are created by sharing objects between threads.

The following example shows how to successfully create a program that abstracts a thread into a C++ class. It can be easily extended to provide a mechanism by which the thread creation and manipulation itself is also encapsulated into the class.


Example

See Code disclaimer information for information pertaining to code examples.

/* This C++ example must be compiled with VisualAge C++ for OS/400 */
#define _MULTI_THREADED
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <pthread.h>

class ThreadClass {
public:
  ThreadClass(char *s) {
    data1 = 42; data2 = strlen(s);
    strncpy(str, s, sizeof(str)-1);
    str[49]=0;
  }
  void *run(void);
private:
   int      data1;
   int      data2;
   char     str[50];
};

extern "C" void *ThreadStartup(void *);

int main(int argc, char **argv)
{
  ThreadClass  *t=NULL;
  pthread_t     thread;
  int           rc;
  // Use printf instead of cout.
  // At the time this test was written, the C++ standard class library
  // was not thread safe.
  printf("Entered test %s\n", argv[0]);

  printf("Create a ThreadClass object\n");
  t = new ThreadClass("Testing C++ object/thread creation\n");

  printf("Start a real thread to process the ThreadClass object\n");
  // #define COMPILE_ERROR
  #ifdef COMPILE_ERROR
  // This is an ERROR. You cannot create a thread by using a pointer
  // to a member function. Thread creation requires a C linkage function.
  // If you remove the comments from the line `#define COMPILE_ERROR'
  // the compiler will give a message similar to this:
  //    "ATESTCPP0.C", line 46.53: 1540-055: (S) "void*(ThreadClass::*)()"
  //    cannot be converted to "extern "C" void*(*)(void*)".
    rc = pthread_create(&thread, NULL, ThreadClass::run, NULL);
  #else
  // Instead, this is the correct way to start a thread on a C++ object
    rc = pthread_create(&thread, NULL, ThreadStartup, t);
  #endif
  if (rc) {
    printf("Failed to create a thread\n");
    exit(EXIT_FAILURE);
  }

  printf("Waiting for thread to complete\n");
  rc = pthread_join(thread, NULL);
  if (rc) {
    printf("Failed to join to the thread, rc=%d\n");
    exit(EXIT_FAILURE);
  }
  printf("Testcase complete\n");
  exit(EXIT_SUCCESS);
}

// This function is a helper function. It has normal C linkage, and is
// as the base for newly created ThreadClass objects. It runs the
// run method on the ThreadClass object passed to it (as a void *).
// After the ThreadClass method completes normally (i.e returns),
// we delete the object.
void *ThreadStartup(void *_tgtObject) {
  ThreadClass *tgtObject = (ThreadClass *)_tgtObject;
  printf("Running thread object in a new thread\n");
  void *threadResult = tgtObject->run();
  printf("Deleting object\n");
  delete tgtObject;
  return threadResult;
}

void *ThreadClass::run(void)
{
  printf("Entered the thread for object %.8x %.8x %.8x %.8x\n", this);

  printf("Object identity:  %d, %d: %s\n", data1, data2, str);
  return NULL;
}

Output

Entered test QP0WTEST/ACPPOBJ
Create a ThreadClass object
Start a real thread to process the ThreadClass object
Waiting for thread to complete
Running thread object in a new thread
Entered the thread for object 80000000 00000000 d017dad2 57001f60
Object identity:  42, 35: Testing C++ object/thread creation
Deleting object
Testcase complete

Top | Pthread APIs | APIs by category