使由函数初始化的变量可用于多线程环境中的函数

Make a variable that is initialized by a function available to a function in multithreaded environment

这就是我要解决的问题,我正在用 C 编程。

我们有一个函数可以为您初始化结构。

typedef struct {
  int val1;
  int val2;
} custom_t;

custom_t init_custom() {
  custom_t temp;

  temp.val1 = 5;
  temp.val2 = 5;


  return temp;
}

您可以像这样使用它:

custom_t some_name = init_custom();

我有 4 个函数将 custom_t 作为输入并可以用它做一些工作。

在另一个文件中,我有很多库函数可以在多线程环境中 运行。无论线程如何,这些库函数都需要对同一个 custom_t 变量进行处理。

库函数不会获得传递给它的 custom_t 变量,因为目标是其他用户应该能够在不考虑 custom_t 变量的情况下使用库函数。

我想我必须在我定义库函数的命名空间中使 custom_t 变量成为全局变量,但我出错说全局变量必须是常量。

我不确定如何实现这一点,如果能得到所有帮助,我将不胜感激。如果我的解释不够好,请随时提出任何问题,我会尽力详细说明。

编辑: 修复了变量初始化错字

对于 custom_t = init_custom();,您正在尝试设置 typename(即 custom_t)。

换个名字就可以了:

custom_t my_global_custom = init_custom();

但是,要从多个线程和库函数访问它,假设您需要写入它,您需要将对此的访问包装在互斥锁中:

pthread_mutex_t custom_mutex = PTHREAD_MUTEX_INITIALIZER;
custom_t my_global_custom;

my_global_custom = init_custom();

// how each thread must access it
pthread_mutex_lock(&custom_mutex);
func_that_uses_my_global_custom();
pthread_mutex_unlock(&custom_mutex);

更新:

我的例子并不是字面上的一个初始化器而是一个赋值

pthread_mutex_t custom_mutex = PTHREAD_MUTEX_INITIALIZER;
custom_t my_global_custom;
custom_t my_global_2;

custom_t
init_custom(void)
{
    custom_t temp;

    temp.val1 = 5;
    temp.val2 = 5;

    return temp;
}

void
init_custom2(custom_t *temp)
{

    temp->val1 = 5;
    temp->val2 = 5;
}

int
main(void)
{

    // either one of these should work ..
    my_global_custom = init_custom();
    init_custom2(&my_global_2);

    // start some threads ...

    return 0;
}

void *
thread_func(void *)
{

    // how each thread must access it:
    pthread_mutex_lock(&custom_mutex);
    func_that_uses_my_global_custom();
    pthread_mutex_unlock(&custom_mutex);

    return (void *) 0;
}

更新#2:

But do you know any way to initialize my_global_custom outside the main function? Or is that just not possible?

另一种方法 [至少在 gcc 下] 是创建一个 contructor 函数。鉴于上述功能和定义,将 init 调用移动到:

void __attribute__((constructor))
my_global_constructor(void)
{

    my_global_custom = init_custom();
    init_custom2(&my_global_2);
}

不需要[并且应该]调用此函数。它会在之前被自动调用 main 因为它现在是一个特殊的函数。

这些经常被想要做一些初始化的库使用,但是不想想要负担 main必须 知道 才能调用(例如)init_liba(); init_libb(); ... 在这种情况下,它会在 "right" 时间为库调用 [基于链接等] .

还有一个__attribute__((destructor))可以用来"destroy"的东西[after main returns, IIRC].

有关这方面的更多信息,请参阅:How exactly does __attribute__((constructor)) work?

就个人而言,我现在使用上述属性,但是,出于怀旧之情,我喜欢较旧的 .init/.fini 部分。

正如您在评论@CraigEstey 的回答时所阐明的那样,问题不在于变量需要 const,而是它的 初始化程序 需要编译-时间常数。解决此类问题的一种方法是通过宏而不是函数 return 值定义静态初始化值。例如,在一些适当的头文件中 declare

typedef struct {
    int val1;
    int val2;
} custom_t;

#define CUSTOM_T_INITIALIZER { .val1 = 5, .val2 = 5 }

然后您可以像这样初始化 custom_t 类型的变量:

custom_t some_name = CUSTOM_T_INITIALIZER;

,包括在文件范围内。

更新:

如果您需要为文件范围或静态持续时间变量分配一个不是编译时常量的值(包括它是否具有聚合类型并且其成员之一所需的值不是编译-时间常数),那么你不能为此目的使用初始化器。相反,您必须安排在程序启动后为该变量分配所需的值,可能是通过调用某种初始化函数。