【问题标题】:single bit manipulation单比特操作
【发布时间】:2011-01-15 15:34:21
【问题描述】:

是否有可能在 C 中只获取一个 int 位然后翻转它而不读取整个 int 并将其写回内存?

上下文: 试图避免 pthread 中的锁定/解锁过多。

【问题讨论】:

    标签: c


    【解决方案1】:

    你不能从内存中读取一个位,实际上你不能强制 CPU 只读取一个字节。它总是读取一个完整的缓存行,对于不同的 CPU,它可能有不同的大小。

    但是从语言的角度来看,你可以使用位域http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html

    【讨论】:

      【解决方案2】:

      据我所知,最低的操作单位是字节。也许您可以将 int 拆分为字节并从 word 中读取所需的字节并仅更改那个。

      【讨论】:

        【解决方案3】:

        没有。为什么会这样,即使您可以从内存中读取一点,您仍然需要锁定以确保它是安全的。

        【讨论】:

          【解决方案4】:

          要么使用可以原子处理的最小类型(char 在任何健全的架构上都可以,但一些 RISC 垃圾不能原子地对单个字节进行操作)并接受你会浪费一些空间,使用锁,或使用正确的原子原语(在 asm、gcc 内置或 C1x _Atomic 类型中)对单个位进行原子算术。

          【讨论】:

            【解决方案5】:

            这就是你如何比爷爷互斥锁快 50 倍(我们对这种事情进行了测试)。使用 gcc 原子操作。如果您的版本包含它们,您也可以使用 linux 原子操作。

            typedef union _foo {
              struct {
                unsigned int a:1,
                             b:6,
                             q:2;
              } Data;
              unsigned int n32;
            } TFoo;
            
            TFoo _GlobalFoo;
            
            SomeFuncThatChangesFoo_A(int fNewA)
            {
            TFoo Old, New;
            
              while(1) {
                // get a copy of the current state
                Old.n32 = _GlobalFoo.n32;
                New.n32 = Old.n32;
                New.Data.a = fNewA;
                // compare and swap is the atomic operation.
                // if _GlobalFoo hasn't changed since we copied it to "Old", then change _GlobalFoo to "New".
                // __sync_bool_compare_and_swap works on basic types (8 bit, 16 bit, 32 bit, 64 bit, 128 bit
                // depending upon architecture), which is why there is a union overlaying the 32 bit n32 over 
                // the actual data that the program uses, Data.
                if (__sync_bool_compare_and_swap(_GlobalFoo.n32, Old.n32, New.n32))
                  break; // successfully changed 
                // if we get here, the global was changed by another thread, so we just loop back, get the new value
                // and try again.
              } // concurrency loop
            }
            

            精明的线程专家可能会认为“Old.n32 = _GlobalFoo.n32;”这一行如果编译器选择非原子方式来执行复制,则可以在竞争中复制垃圾。但是,__sync_bool_compare_and_swap 会因为当前状态的错误副本而失败,因此不会造成任何伤害。

            干杯。

            【讨论】:

              【解决方案6】:

              这可能是可能的,但只能以非便携式、非标准方式,并且只有在您的平台支持的情况下。一些 ARM CPU(例如 Cortex-M3 和 M4)实现了“位带”,为地址空间区域提供位级寻址。

              但一般来说,读/写的最小单元(或等效的最小可寻址单元)是char。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-02-09
                • 2019-03-20
                • 2020-09-14
                • 1970-01-01
                • 1970-01-01
                • 2019-02-25
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多