代码之家  ›  专栏  ›  技术社区  ›  Nate

启动(等)是否可重入?

  •  5
  • Nate  · 技术社区  · 15 年前

    在对一个历史悠久的类进行编辑时,架构师的一个特殊习惯使我陷入了困境,他用互斥锁包装自己的va廑start->va廑end序列。这个添加的变更日志(大约15年前做的,此后没有修改)指出,这是因为va_start et.all不可重入。

    我不知道vaúu start有任何这样的问题,因为我一直认为它只是一些堆栈指针数学的宏。这里有什么我不知道的吗?如果有副作用的话,我不想更改这个代码。

    具体来说,所讨论的函数非常类似于:

    void write(const char *format, ...)
    {
        mutex.Lock();
        va_list args;
        va_start(args, format);
        _write(format, args);
        va_end(args);
        mutex.Unlock();
    }
    

    这是从多个线程调用的。

    3 回复  |  直到 15 年前
        1
  •  6
  •   Michael Burr    15 年前

    至于串行可重入(即,如果 foo() va_start 它安全吗 福() 打电话 bar() 虚拟开始 va_list 实例不一样。标准上说,

    在没有对同一ap的va-end宏进行干预调用的情况下,不应调用va-start或va-copy宏来重新初始化ap。

    所以,你没事只要 (以上简称 ap

    如果您所说的可重入是指线程安全(我假设您是这样的,因为涉及互斥锁),那么您需要查看具体的实现。由于C标准不讨论多线程,所以这个问题实际上是由实现来确保的。我可以想象这可能很难 虚拟开始 在一些古怪或小型架构上是线程安全的,但我认为如果你在一个现代主流平台上工作,你可能不会遇到任何问题。

    在更主流的平台上 虚拟开始 宏多个线程通过“同一个”应该没有问题 虚拟开始 瓦乌名单 参数通常在堆栈上(因此不同的线程将有不同的实例),您通常处理 瓦乌名单 .

    我认为在您的示例中,对于varargs使用互斥是不必要的。但是,如果 write() ,对于 要序列化的调用,以便您没有多个 写入() 螺纹把彼此的输出搞砸了。

        2
  •  2
  •   AnT stands with Russia    15 年前

    好吧,在C中实现变量参数访问的方式使得 va_list 内部状态 . 这使得它不可重入,这意味着调用 va_start 在一个 对象将使前一个 . 但更确切地说,C 调用 虚拟开始 在“关闭”以前调用的 虚拟开始 va_end .

    对象应该以“非重叠”方式使用: va_start...va_end . 在那之后你可以做另一个 虚拟开始 瓦乌名单 反对。但是试图 这个 相同的会话 瓦乌名单 对象将不起作用。

    实际上,在理论上,当然,在任何基于会话的迭代器中都可以实现一些基于后进先出的内部状态。一、 e.理论上可以允许嵌套 开始…结束 相同的会话 瓦乌名单 对象(从而使其在这种意义上可重入)。但是C库规范没有提供类似的东西。

    瓦乌名单 对象可由复制 va_copy . 所以,如果需要通过几个重叠的参数来浏览同一个参数列表 开始…结束 会话,您始终可以通过创建原始文件的多个独立副本来实现这一点 瓦乌名单

    P、 附则。 看看你提供的代码示例。。。在这种情况下,绝对不需要任何互斥锁(只要 瓦乌名单 担心)。不需要重入 瓦乌名单 反对。在没有任何互斥锁的情况下,您的代码非常好。它将在多线程环境中正常工作。宏来自 va_... 组不在实际的“堆栈指针”上操作。相反,他们是完全独立的 对象,可用于对堆栈中存储的值进行迭代。您可以将其视为您自己的私有本地堆栈指针。调用函数的每个线程都将获得它自己的副本 瓦乌名单 在自己的堆栈上迭代。线程之间不会有冲突。

        3
  •  0
  •   supercat    15 年前

    在有些平台上,虚拟企业列表可能会遇到重新进入的问题,但在同一个平台上 全部的