为什么 `pthread_rwlock_t` 的 ABI 在不同版本之间差异很大?

Why `pthread_rwlock_t`'s ABI differs a lot among versions?

我正在研究 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?

  1. Why pthread_rwlock_t changes this much among versions? Is it because it want to support more features, or enhance performance?

因为 glibc 维护者认为更改它可以获得优势。

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

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

  1. Is there any ways I can may GLIBC2.30 and GLIBC2.17 operate the same rwlock?

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

are different versions of GLIBC not compactible with each other?

很明显,您的特定问题涉及的两个版本与您希望的方式不兼容。 Glibc 在 link 兼容性方面相当不错:

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

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

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

So I can't use shm between different versions of GLIBC?

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

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