CreateThread包装函数

时间:2017-06-27 07:28:30

标签: c multithreading winapi

我目前正在开发一个项目,我们使用pthreads为UNIX系统提供C线程实现。现在我们希望能够在Windows上运行整个项目,我正在翻译WIN32的所有线程。现在我遇到了一个问题,我无法想出一个像样的解决方案。

我有thrd_create()功能:

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;
}

该函数应该创建一个新线程,并且用户提供一个启动函数。为方便起见,我想保留调用thrd_create()的实现,如果可能的话。出于这个原因,我创建了一个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;
}

我的问题是:我的包装函数应该返回什么DWORD?用户为pthread实现提供的函数具有void返回类型,因此我不会从中获得任何结果。有什么建议吗?

修改

Args看起来像这样:

struct Args {
    void (*function)(void * aArg);
    void* arg;
};
typedef struct Args Args;

1 个答案:

答案 0 :(得分:0)

根据手册,最好坚持使用正确的签名并使用返回值:

  1. Windows
  2. Pthreads
  3. 另一个值得关注的问题是args的生命周期,我说最好的方法是让调用者清理,所以需要跟踪你的线程直到它终止。

    近似的API可能与以下内容类似:

    /* 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);
    

    一个近似的实现方式是:

    #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看起来有点像这样。

    error_t func(void* args) {
      return OK;
    }
    
    .....................
    
    thread_t t = { .func = func, .args = NULL };
    thread_create(&t);
    

    显然,您需要实施自己的取消,结果收集,加入......