【问题标题】:How to avoid code bloat when using pthreads in C?在 C 中使用 pthread 时如何避免代码膨胀?
【发布时间】:2015-02-04 20:37:44
【问题描述】:

在用 C 编写线程代码时,我首先必须创建一些 struct,其中包括所有参数和一个包装函数。这会导致大量代码膨胀并且不易阅读。见:

struct some_function_args {
  int arg1;
  int arg2;
  int arg3;
};

void some_function_wrapper(struct some_function_args* args) {
  some_function(args->arg1, args->arg2, args->arg3);
}

int main() {
  struct my_args;
  my_args.arg1 = 1;
  my_args.arg2 = 2;
  my_args.arg3 = 3;

  pthread_create(..., some_function_wrapper, &my_args);
  pthread_join(...);
}

是否有某种宏或库(可能使用varargs)自动为我创建所需的结构和包装函数,像这样?或者这在 C 中根本不可能?

int main() {
  MY_THREAD thread = IN_THREAD {
    some_function(1, 2, 3);
  }

  JOIN_THREAD(thread);
}

【问题讨论】:

  • 请注意,some_function_wrapper 应采用 void* 并将其显式转换为 struct some_function_args*。否则它将被错误的原型调用,这是未定义的行为。
  • 较新的 C 标准 (C99) 具有复合初始化器:struct my_args = {.arg1 = 1, .arg2 = 2, .arg3 = 3};

标签: c multithreading pthreads c-preprocessor


【解决方案1】:

编辑:我发布了一些代码。见threadify.h

使用以下宏,您可以执行以下操作:

char a = 'A';
int  b = 23;
char[] c = "Example";


pthread_t thread;

// THREAD3 because it takes 3 arguments of variable type.
THREAD3(thread, a, b, c, {
  printf("test: %c %d %s\n", a, b, c);
});

JOIN(thread);

在 GCC 中是可能的,因为 GCC 有两个非标准扩展:

  • 嵌套函数
  • typeof() 运算符

在这个庞大的宏中存在一些缺点:

  • 您不能传递右值(因为无法创建指向它们的指针)
  • 您需要根据参数的数量使用适当的THREAD0THREAD1、...宏(不确定是否可以使用可变参数宏来解决此问题)。

    #include <stdio.h>
    #include <pthread.h>
    
    // Nested definition to work around preprocessor prescan
    #define __CAT(arg1, arg2) arg1 ## arg2
    #define CAT(arg1, arg2) __CAT(arg1, arg2)
    
    // Use the current line number to create a unique name for objects
    #define NAME(arg1) CAT(arg1, __LINE__)
    
    // Creates a thread without any arguments
    #define THREAD0(thread, code) \
    void NAME(__pthread_wrapper)(void) {\
      do {code;} while(0); \
    }; \
    pthread_create(&thread, NULL, (void*)NAME(__pthread_wrapper), NULL);
    
    // Creates a thread with one argument by creating a struct
    // and passing all values via this struct.
    #define THREAD1(thread, arg1, code) \
    typedef struct { \
      typeof(arg1)* NAME(__pthread_arg1); \
    } NAME(__pthread_struct); \
      void NAME(__pthread_wrapper)(NAME(__pthread_struct)* data) {\
      do {code;} while(0); \
    }; \
    NAME(__pthread_struct) NAME(__data); \
    NAME(__data).NAME(__pthread_arg1) = &arg1; \
    pthread_create(&thread, NULL, (void*)NAME(__pthread_wrapper), &NAME(__data));
    
    #define THREAD2(thread, arg1, arg2, code) \
    typedef struct { \
      typeof(arg1)* NAME(__pthread_arg1); \
      typeof(arg2)* NAME(__pthread_arg2); \
    } NAME(__pthread_struct); \
      void NAME(__pthread_wrapper)(NAME(__pthread_struct)* data) {\
      do {code;} while(0); \
    }; \
    NAME(__pthread_struct) NAME(__data); \
    NAME(__data).NAME(__pthread_arg1) = &arg1; \
    NAME(__data).NAME(__pthread_arg2) = &arg2; \
    pthread_create(&thread, NULL, (void*)NAME(__pthread_wrapper), &NAME(__data));
    
    #define THREAD3(thread, arg1, arg2, arg3, code) \
    typedef struct { \
      typeof(arg1)* NAME(__pthread_arg1); \
      typeof(arg2)* NAME(__pthread_arg2); \
      typeof(arg3)* NAME(__pthread_arg3); \
    } NAME(__pthread_struct); \
      void NAME(__pthread_wrapper)(NAME(__pthread_struct)* data) {\
      do {code;} while(0); \
    }; \
    NAME(__pthread_struct) NAME(__data); \
    NAME(__data).NAME(__pthread_arg1) = &arg1; \
    NAME(__data).NAME(__pthread_arg2) = &arg2; \
    NAME(__data).NAME(__pthread_arg3) = &arg3; \
    pthread_create(&thread, NULL, (void*)NAME(__pthread_wrapper), &NAME(__data));
    
    /* THREAD4, THREAD5, ... */
    
    #define JOIN(thread) pthread_join(thread, NULL);
    

【讨论】:

  • 也许你可以像这样在一对括号中隔离参数:THREAD(thread, (a, b, c), {...})?我不是 PP 专家,但我见过在 Boost 中完成的一些疯狂的事情,这看起来很基本。
  • 然后我仍然需要以某种方式遍历它们以创建结构。也许我可以使用以下技术构建一些#for VAR in (a,b,c) 循环:stackoverflow.com/a/10542793/773690
  • Boost PP 在这里可能会有很大用处。另外请查看my comment above 关于函数指针的信息。这种方式可能会奏效,但比抱歉更符合标准。
【解决方案2】:

'在用 C 编写线程代码时,我首先必须创建一些结构,其中包含所有参数和一个包装函数。这会导致大量代码膨胀并且不易阅读。当然。这就是你为制作你的应用程序所付出的代价,(假设它并不愚蠢),要么快 X 倍,要么更容易实现 X 倍,因为它更容易被描述为独立的功能。你想不劳而获?

【讨论】:

    猜你喜欢
    • 2018-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-04
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多