【问题标题】:CreateThread wrapper functionCreateThread 包装函数
【发布时间】:2017-11-30 04:02:16
【问题描述】:

我目前正在从事一个项目,我们使用 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;

【问题讨论】:

  • 什么是Args?
  • 为什么不直接返回零呢? Windows 实际并未使用线程返回的值。这不是类似于您已经对 pthreads 所做的事情吗(因为 pthreads 线程函数返回 void *)?
  • @Someprogrammerdude 我认为你刚刚打破了我和解决方案之间的墙。你是对的,如果有的话,返回值会引起用户的兴趣。而用户是……我。
  • @ZerO 您使用的是哪个编译器和版本?

标签: c multithreading winapi


【解决方案1】:

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

  1. Windows
  2. Pthreads

另一个值得关注的问题是 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

调用看起来有点像这样。

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

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

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

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

【讨论】:

    猜你喜欢
    • 2018-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 1970-01-01
    • 2021-02-27
    相关资源
    最近更新 更多