在 C 中,函数指针变量对于多线程(线程安全)(原子)总是定义/合法吗?

问题描述 投票:0回答:2

编辑:问题的意思是“函数指针在 C 标准中是原子的”。

变量(即指向函数本身的指针)是线程安全的吗? 对于线程安全,我的意思是,值总是定义的吗? 比如,它总是一个合法值,即现有函数的地址吗? (我在某个时刻分配给这个值的一些函数。)

我认为将值存储在变量中应该始终是单个汇编指令(类似于“读取”)。考虑到这一点,应该没问题吧?

注意:我的意思是在单核 CPU 上。 (我不确定这是否有影响。)

例如,对于代码,下面代码中的

set_a()
do_something()
可以随时从任何线程调用。

测试.h

typedef int fn_t (int a);

void set_a(fn_t * fn);

void do_something(void);

测试.c

static fn_t * a;

void set_a(fn_t * fn){
    a = fn;
}

void do_something(void){

    if (a != NULL && a(1) == 0){
        printf(" Happend \n");
    }

    printf("Doing something else \n");
}
c multithreading thread-safety function-pointers atomic
2个回答
1
投票

变量(即指向函数本身的指针)是线程安全的吗?对于线程安全,我的意思是该值总是定义的吗?就像它总是一个合法值,一个现有函数的 adr 一样。

不,无论线程如何。 对象指针和函数指针都不能自动保证包含有效目标的地址。 例如,

void (**p)(void) = malloc(sizeof(*p));

void (*fp1)(void) = (void (*)(void)) 0;
void (*fp2)(void) = (void (*)(void)) *p;

但是,确实所有函数都存在并在程序的整个运行过程中保持相同的地址,因此一旦获取现有函数的地址,结果就永远不会成为悬空指针。

函数及其地址也不是特定于线程的。 在一个线程中有效的函数指针也是有效的,并且在程序的同一运行中指向任何其他线程中的相同函数。

我认为将值存储在变量中应该始终是单个汇编指令(类似于“读取”)。考虑到应该没问题,不是吗?

这与线程安全关系不大,也不是函数指针的特殊特性。 您所问的问题似乎更像是对函数指针类型的对象的访问是否是“原子”的。 但在 C 语言级别,这与任何给定 CPU 如何实现该类型值的读写没有太大关系。 C 具有明确的原子类型,但它无法识别任何意外的原子类型。

代码示例,set_a() 和 do_something() 可以随时从任何线程调用。

如果一个线程调用您的
set_a()

,而另一个线程调用您的

do_something()
,并且这些调用之间没有任何同步,则该程序包含数据争用,并且其行为未定义。 只要
a
的类型不是原子的,无论其具体类型是什么,都是如此。
    


1
投票
变量(即指向函数本身的指针)是线程安全的吗?

您问错了问题。
variable

是否是“线程安全”(无论这意味着什么*)并不重要。 您的代码线程安全的方式使用变量。 这个表达式,

a != NULL && a(1) == 0

首先测试值,然后使用指针。没有什么可以阻止其他线程更改测试和使用之间的值。

线程安全的变量和对象不会神奇地为使用它们的代码赋予线程安全性。一个程序作为一个整体不是“线程安全的”,除非它在每个级别都是线程安全的。

* 如果有人说变量是“线程安全的”,他们通常意味着没有线程会看到该变量包含除其初始值或程序存储在其中的值之外的任何值。我不知道 C 指针变量是否总是具有该属性。

© www.soinside.com 2019 - 2024. All rights reserved.