单位操作

时间:2011-01-15 15:34:22

标签: c

是否可以在C中只获取一个int,然后在不读取整个int并将其写回内存的情况下翻转它?

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

6 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

要么使用可以原子方式寻址的最小类型(char在任何理智的架构上都可以,但是某些RISC垃圾不能在单个字节上进行原子操作)并接受你将浪费一些空间,使用锁定,或使用正确的原子基元(在asm,gcc builtins或C1x _Atomic类型中)对各个位进行原子运算。

答案 4 :(得分:1)

以下是你如何做到比爷爷互斥体快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会因为当前状态的错误副本而失败,因此不会造成任何伤害。

欢呼声。

答案 5 :(得分:0)

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

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