4
votes

I am currently working on a project where we have a C thread implementation for UNIX systems using pthreads. Now we want to be able to run this entire project on Windows as well, and I am translating all the threading for WIN32. Now I encountered a problem for which I could not come up with a decent solution.

I have the thrd_create() function:

static inline int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) {
    Args* args = malloc(sizeof(Args));
    args->arg = arg;
    args->function = func;
    *thr = CreateThread(NULL, 0, wrapper_function, (LPVOID) args, 0, NULL);
    if (!*thr) {
        free (args);
        return thrd_error;
    }
    return thrd_success;
}

This function is supposed to create a new thread, and the user provides a start function. For convenience, I would like to leave the implementation that calls thrd_create() untouched if possible. For this reason, I created a wrapper_function:

static inline DWORD wrapper_function(LPVOID arg) {
    Args * args;
    args = (Args*) arg;
    DWORD res = args->function(args->arg); //This does obviously not work
    return res;
}

My question is: What DWORD should my wrapper function return? The function provided by the user for the pthread implementation has void return type, so I won't get any result from that. Any suggestions?

EDIT

Args looks like this:

struct Args {
    void (*function)(void * aArg);
    void* arg;
};
typedef struct Args Args;
1
What is Args? - Jabberwocky
Why not just return zero? The threads returned value isn't actually used by Windows. Isn't that something similar to what you already have to do with pthreads (since the pthreads thread function returns a void *)? - Some programmer dude
@Someprogrammerdude I think you just crushed the wall that was between me and the solution. You are right, if anything, the return value would be of interest for the user. And the user is... me. - PKlumpp
@ZerO Which compiler and version are you using? - cse

1 Answers

0
votes

According to manuals it is better to stick to a correct signature and use return value:

  1. Windows
  2. Pthreads

The other matter of concern would be the lifetime of args, I'd say the best way is for a caller to clean up, so they need to be tracked with your thread until it terminates.

An approximate API could be something along the lines of the following:

/* Your general error codes enumeration
 * which should probably reside in a general
 * header 
 */
typedef enum {
  OK = 0,
  // Your application specific error codes
} error_t;

#ifdef _WIN32
  #include <Windows.h>
  typedef HANDLE thread_handle_t;
#else // assume pthreads
  #include <pthread.h>
  typedef pthread_t thread_handle_t;
#endif

typedef error_t(*entry_func_t)(void*);

typedef struct {
  entry_func_t     func;
  void             *args;
  error_t          _result;
  thread_handle_t  _handle;
} thread_t;

// returns OK(0) on success
// returns error code indicating a problem
error_t thread_create(thread_t *t);

An aproximate implementation would be:

#ifdef _WIN32
  DWORD _win_entry_f(void *args) {
    thread_t *t = args;
    t->_result = t->func(t->args);
    return 0; // Or some other Windows-specific value
  }

  error_t thread_create(thread_t *t) {
    error_t err = OK;
    if(!(t->_handle = ThreadCreate(NULL, 0, _win_entry_f, t, 0, NULL))) {
      switch (GetLastError()) {
        // Populate error with code
      }
    }
    return err;
  }
#else
  void * _pthread_entry_f(void *args) {
    thread_t *t = args;
    t->_result = t->func(t->args);
    return NULL; // Or some other pthreads specific value
  }

  error_t thread_create(thread_t *t, entry_func_t func, void *args) {
    error_t err = OK;
    switch(pthread_create(&t->_handle, NULL, _pthread_entry_f, t)) {
    case 0: break;
    // other cases populate err
    }
    return err;
  }
#endif

Invokation would look somewhat like this.

error_t func(void* args) {
  return OK;
}

.....................

thread_t t = { .func = func, .args = NULL };
thread_create(&t);

Obviously you'll need to implement your own cancelation, result collection, join, ...