初始化:函数与文字

Initialization: Function vs. literal

我注意到,在像 libpthread 这样的库中,会有一些结构可以通过两种方式之一进行分配。例如,一个 pthread_mutex_t 可以通过

静态初始化
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

或动态地通过

pthread_mutex_init(&lock);

但是,除非我遗漏了什么,否则 pthread_mutex_init 函数是多余的。也就是说,我不能做吗

lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;

?

pthread_mutex_init() 的声明是:

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
                       const pthread_mutexattr_t *restrict attr);

因此您可以通过函数调用向初始化程序提供选定的属性,而您不能通过使用 PTHREAD_MUTEX_INITIALIZER 的赋值。

但是,如果您对默认属性感到满意,那么没有明显的理由说明您不能使用 'compound literal' 赋值符号。

请注意,通过赋值重新初始化它来 'destroy' 以前使用过的互斥量是不明智的。始终使用 pthread_mutex_destroy() 函数来销毁互斥锁​​。如果您为互斥锁使用局部变量,请确保它始终在变量超出范围之前被销毁。并且不要在使用时销毁互斥量。上面引用的 POSIX 页面涵盖了其中的许多要点。

如果我没记错的话函数声明如下

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
    const pthread_mutexattr_t *restrict attr);

也就是说它有两个参数。

可以为已经存在的互斥调用该函数,并且用户可以指定除默认互斥属性之外的任何可接受的属性。

至于宏PTHREAD_MUTEX_INITIALIZER则根据描述

In cases where default mutex attributes are appropriate, the macro PTHREAD_MUTEX_INITIALIZER can be used to initialize mutexes that are statically allocated. The effect is equivalent to dynamic initialization by a call to pthread_mutex_init() with parameter attr specified as NULL, except that no error checks are performed.

That is, couldn't I just do

lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;

?

PTHREAD_MUTEX_INITIALIZER 扩展为适合 pthread_mutex_t 类型对象的初始值设定项,在文件范围内声明。这必须采用 brace-enclosed 初始化列表或与 pthread_mutex_t.

兼容的类型常量的形式
  • 如果它是一个 brace-enclosed 初始化列表 那么在它前面加上 (pthread_mutex_t) 会产生一个 [=12= 类型的复合文字].只要不是数组类型,并且它不直接或间接包含任何 const 成员,C 语言允许这样的赋值。

  • 如果它是与 pthread_mutex_t 兼容的类型的常量,则在其前面加上 (pthread_mutex_t) 形成一个类型转换表达式,它C 语言仅在 pthread_mutex_t 为 void 或标量类型时才允许。此类别中的一个合理可能的替代方案是 pthread_mutex_t 是结构类型并且 PTHREAD_MUTEX_INITIALIZER 扩展为复合文字,并且在这种情况下转换将违反语言约束。

那么,从 C-language 的角度来看,假设您可以执行这样的任务是不安全的。

从POSIX的角度来看,规范没有指定PTHREAD_MUTEX_INITIALIZER的扩展形式,也没有指定它适合您描述的用途。 POSIX-conforming 因此,C 实现可以自由地使用他们希望的任何类型的 built-in 或 special-casing 来实现它,并且除了将其用作初始化程序之外,不需要正确处理任何情况。

从这两个角度来看,不,按照你描述的那样做是不安全的。

此外,正如其他答案所观察到的,初始化宏仅适用于您对默认互斥锁属性感到满意的情况。如果你想要 non-default 属性,比如一个健壮的或 process-shared 互斥锁,那么你必须使用 pthread_mutex_init() 来获得它们。尽管如此,那么,不,pthread_mutex_init() 并不是多余的。