【问题标题】:Why `pthread_rwlock_t`'s ABI differs a lot among versions?为什么`pthread_rwlock_t`的ABI在不同版本之间有很大差异?
【发布时间】:2021-03-21 15:50:19
【问题描述】:

我正在研究pthread_rwlock_t 的不同实现版本。

  1. GLIBC2.30

    typedef union
    {
      struct __pthread_rwlock_arch_t __data;
      char __size[__SIZEOF_PTHREAD_RWLOCK_T];
      long int __align;
    } pthread_rwlock_t;
    
    struct __pthread_rwlock_arch_t
    {
      unsigned int __readers;
      unsigned int __writers;
      unsigned int __wrphase_futex;
      unsigned int __writers_futex;
      unsigned int __pad3;
      unsigned int __pad4;
      ...
    
  2. GLIBC2.17

    typedef union
    {
    # ifdef __x86_64__
      struct
      {
        int __lock;
        unsigned int __nr_readers;
        unsigned int __readers_wakeup;
        unsigned int __writer_wakeup;
        unsigned int __nr_readers_queued;
        unsigned int __nr_writers_queued;
        int __writer;
        int __shared;
    ...
    
    } pthread_rwlock_t;
    

他们的实现似乎不同,给我带来了一些困难。因为我有一个链接到 GLIBC2.30 的程序 a 和一个链接到 GLIBC2.17 的程序 b。这两个程序都将在 shm 上共享的同一 pthread_rwlock_t 上运行。我通过静态链接 GLIBC 实现了这一点。

但是,GLIBC2.30 和 GLIBC2.17 会以不同的方式解释 shm 上的 pthread_rwlock_t 对象,因为它们的定义不同。例如,如果 __readers 被 GLIBC2.30 设置为 2,然后被 GLIBC2.17 访问,它会认为 pthread_rwlock_t 被锁定并休眠。但是,pthread_rwlock_t 未锁定。

我的问题是:

  1. 为什么pthread_rwlock_t 在版本之间变化如此之大?是因为它想支持更多功能,还是想提高性能?
  2. 有什么方法可以让 GLIBC2.30 和 GLIBC2.17 运行相同的 rwlock?

更新

我查看了更多源代码,发现:

  1. GLIBC2.17使用lll_lock实现
  2. GLIBC2.30 使用原子操作哟实现

那我还有一个问题,不同版本的 GLIBC 是不是不能相互压缩?所以我不能在不同版本的 GLIBC 之间使用 shm?

【问题讨论】:

  • I achieved this by staticly linking GLIBC 那么你为什么在乎呢? For example, if __readers is set to 2 你是访问pthread_rwlock_t 类型的内部结构还是使用only pthread_rwlock_* 访问器? (即使你确实使用了,你也静态链接了 glibc。所以.. 你为什么在乎?)
  • 1.不同的 GLIBC 链接程序将在同一个 shm 上运行,这会导致问题,所以我很在意。 2.调用pthread_rwlock_wrlock时,会设置__readers__lock
  • 两个glibc链接程序之间的通信仍然是由内核完成的,而不是glibc。
  • 我通过静态链接 GLIBC 实现了这一点。 这个问题提供了一个完美的例子来说明为什么不静态链接 GLIBC
  • 完全是 GLIBC 问题,与内核无关 不,这是你的问题。您决定将需要在二进制级别交互的两个程序静态链接到两个不同版本的 GLIBC。你:“医生,我这样做的时候很痛。”医生:“不要那样做。”

标签: c pthreads glibc


【解决方案1】:
  1. 为什么 pthread_rwlock_t 在不同版本之间变化如此之大?是因为它想支持更多功能,还是想提高性能?

因为 glibc 的维护者认为改变它会有好处。

与标准标题定义的大多数结构一样,struct pthread_rwlock_t 的布局不是标准化的。与某些此类结构一样,甚至没有任何成员名称是标准化的。我认为结构不是完全不透明的原因是可以直接声明实例,而不是要求它们由某种构造函数生成。

如果您构建的程序依赖于该结构的特定布局,那么您将走投无路,除非您构建的 pthreads 版本提供了什么。 那个定义是由编译时使用的pthreads.h的版本提供的,必须和对应的库匹配。

  1. 有什么方法可以让 GLIBC2.30 和 GLIBC2.17 运行相同的 rwlock?

我想您已经知道答案是否定的。每个库实现都直接依赖于该结构的特定布局,并且布局根本不重合。如果您想在进程之间共享 pthreads rwlock,那么除了配置其 pshared 属性外,您还应该针对相同版本的 libpthread 及其头文件(或任何提供 pthreads 实现的库)构建协作程序。一些版本偏差在实践中可能是可以接受的,但如果您想冒险,那么您需要测试和验证特定的组合。

不同版本的 GLIBC 是否不能相互压缩?

显然,与您的特定问题有关的两个版本与您希望的方式不兼容。 Glibc 对 link 的兼容性非常好:

  • 与一个版本动态链接的程序很可能与更高版本的共享库正确互操作;和

  • 针对一个版本正确构建和静态链接的程序几乎肯定会针对更高版本正确构建和静态链接,甚至使用从 C 语言标准中删除的函数(我在看着你,@987654324 @)。

但是对于库提供的大多数结构类型的一致内部表示,没有要求,也没有合理的期望。请注意,即使只是添加成员,从而改变类型的大小,也会产生不兼容的表示。

所以我 不能在不同版本的 GLIBC 之间使用 shm?

在针对不同版本的 Glibc 构建的程序之间共享内存可能可以使用您根据 C 语言的内置数据类型完全定义的数据类型 (int, @ 987654326@, etc.) 和具有标准化表示的那些 (int32_t, etc.)。然而,原则上,即使是内置数据类型的表示也可能在版本之间发生变化。

我想可能有专门为此目的而设计的 C 库(虽然我不知道),但总的来说,C 实现很少保证内存中数据表示的兼容性。通常,您不能依赖库的不同版本来提供大多数其他数据类型的可互操作的内存中表示。

【讨论】:

    猜你喜欢
    • 2013-12-12
    • 2014-08-31
    • 2011-01-07
    • 2020-06-28
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 2012-03-29
    • 1970-01-01
    相关资源
    最近更新 更多