single bit manipulation
is it possible to get just one bit of an int in C an开发者_如何学编程d then flip it without reading the entire int and writing it back to memory?
context: trying to avoid too many locks/unlocks in pthread.
You can not read a single bit from the memory, actually you can not force CPU to read only a single byte. It is always reading a full cache line, which could have different sizes for different CPUs.
But from the language point of view you can use bit fields http://publications.gbdirect.co.uk/c_book/chapter6/bitfields.html
As far as I know, the lowest unit of operation is the byte. Maybe you can split the int into bytes and read the required byte from the word and change only that one.
No. Why would it, even if you could read one bit from memory you'll still need locking to make sure it's safe.
Either use the smallest type that can be addressed atomically (char
is fine on any sane architecture, but some RISC junk cannot atomically operate on individual bytes) and accept that you'll be wasting some space, use a lock, or use the right atomic primitives (in asm, gcc builtins, or C1x _Atomic
types) for atomic arithmetic on individual bits.
Here is how ya do it 50x faster than grandpa mutex (we did tests on this sort of thing). Use gcc atomic operations. You could also use linux atomic operations if your release included them.
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
}
Astute threaders might think that the line "Old.n32 = _GlobalFoo.n32;" could copy garbage in a race if the compiler chose a non-atomic way to perform the copy. However, __sync_bool_compare_and_swap would just fail because of the a bad copy of the current state, so there would be no harm done.
cheers.
This might be possible, but only in a non-portable, non-standard way and only if your platform supports it. Some ARM CPUs (Cortex-M3 and M4 for example) implement 'bit-banding' that provides bit level addressing to regions of address space.
But in general, the smallest unit for reading/writing (or equivalently, the smallest addressable unit) is a char
.
精彩评论