Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何使pthreads池运行任意例程_C_Multithreading_Pthreads - Fatal编程技术网

C 如何使pthreads池运行任意例程

C 如何使pthreads池运行任意例程,c,multithreading,pthreads,C,Multithreading,Pthreads,我正在使用pthreads实现一个线程池。所有线程共享一个工作队列,主机主线程将工作推送到该共享队列中。我的实现将被用作一个库,它应该能够运行任何应用程序,因此我希望这里的工作是一个具有任意数量参数的任意例程。我在网上搜索了这个,但没有找到任何解决办法 大多数实现的一部分如下所示: typedef struct { void* (*routine)(void*); // work routine void* arg; //work routine argument } _work; t

我正在使用pthreads实现一个线程池。所有线程共享一个工作队列,主机主线程将工作推送到该共享队列中。我的实现将被用作一个库,它应该能够运行任何应用程序,因此我希望这里的工作是一个具有任意数量参数的任意例程。我在网上搜索了这个,但没有找到任何解决办法

大多数实现的一部分如下所示:

typedef struct
{
  void* (*routine)(void*); // work routine
  void* arg; //work routine argument
} _work;

typedef struct
{
  _work *work;
  pthrea_mutex_t work_lock;
  pthread_cond_t work_ready;
} _tpool;

static _tpool *tpool = NULL;

void* thread_routine(void* args)
{
  _work *work;
  while(1){
    pthread_mutex_lock(&tpool->work_lock);
    while(!tpool->work){
        pthread_cond_wait(&tpool->work_ready, &tpool->work_lock);
    }
    work = tpool->work;
    pthread_mutex_unlock(&tpool->work_lock);
    work->routine(work->arg);
  }
  return NULL;
}
typedef struct
{
  void* (*routine)(void*); // work routine
  void** args; // point to a list of arguments
  int num_args; // number of arguments
} _work;
创建线程时,线程将等待工作被推入工作队列。在本例中,我假设队列中只有一个工作。这里的问题是工作例程只有一个参数,尽管如果它是C中的结构,这个参数可能包含多个参数。如果给定了一个应用程序,我们可以很容易地定义这样的结构,但由于它是一个库,它应该处理任意的应用程序。问题是如何处理具有未知参数数的任意例程

例如,我希望实现如下:

typedef struct
{
  void* (*routine)(void*); // work routine
  void* arg; //work routine argument
} _work;

typedef struct
{
  _work *work;
  pthrea_mutex_t work_lock;
  pthread_cond_t work_ready;
} _tpool;

static _tpool *tpool = NULL;

void* thread_routine(void* args)
{
  _work *work;
  while(1){
    pthread_mutex_lock(&tpool->work_lock);
    while(!tpool->work){
        pthread_cond_wait(&tpool->work_ready, &tpool->work_lock);
    }
    work = tpool->work;
    pthread_mutex_unlock(&tpool->work_lock);
    work->routine(work->arg);
  }
  return NULL;
}
typedef struct
{
  void* (*routine)(void*); // work routine
  void** args; // point to a list of arguments
  int num_args; // number of arguments
} _work;
线程例程()
中,它应该启动

work->routine(work->args[0], work->arg[1], work->arg[2], ...);
这里的要点是,我们不知道线程将执行什么例程。这可以是任何常规。例如,这里的例程可以是:

work_1(int a);

work_2(int a, double b)

work_3(float* a, int c, double* b);

对如何实现这一目标有何建议?谢谢。

看看
va_arg
。这就是printf()之类的函数可以接受任意数量的参数的方式。从C99开始,您可以使用
va\u copy()
复制
va\u列表。因此,我猜想,如果您可以创建一个接受可变数量参数的
queuework()
函数,那么您可以使用
va_list
将参数列表复制到一个结构中,然后在调度时将其展开。

有几种方法:

您可以要求例程具有
void*work(void*arg)
routine。如果客户端需要传递多个参数,可以将参数打包到结构中,并传递指向该结构的指针:

struct add_ctx {
    int a, b;
    int result;
}
void *work_add (void *data)
{
    struct add_ctx *args = data;
    args->result = args->a + args->b;
}
/* Queue work order */
struct add_ctx args = { 2, 4, 0 }; // or better allocate on heap
queue_work (work_add, &add_ctx);
// wait for finish job
printf ("result: %d\n", args.result);

您可以为预期的函数签名创建函数“调用接口”描述:

enum Type { INT, INTPTR };
struct ParamDesc {
    enum Type *param_types;
    int n_params;
    void *(*marshaller)(void);
};
/* Marshaller for void* f(int,int,int*) */
void *call_INT_INT_INTPTR (void *(*fn)(int,int,int*), void *opaque_args) {
    int a = unpack_int(opaque_args);
    int b = unpack_int(opaque_args);
    int *c = unpack_pointer(opaque_args);
    return fn(a,b,c);
}
/* Marshallers for other types... */

struct ParamDesc desc = {{INT,INT,INTPTR}, 3, call_INT_INT_INTPTR};

void *work_add (int a, int b, int *result)
{
    *result = a + b;
}

/* Queue work order */
int a,b, result;
queue_work(&desc, work_add, a, b, &result);
/* queue_work is variable arguments function that has to somehow
  pack arguments according to ParamDesc it receives */
这需要相当多的样板代码,但其中大部分可以自动生成。看看它是如何在Glib中完成的:


您可能会使用图书馆,如

谢谢。我认为这是最终的解决方案,尽管我认为这将很难实现。谢谢。现在我有五种不同类型的例程要推送到队列中,所以我计划将这些例程的所有参数打包到一个结构中。