So I read that in a 32bit machine, one can use the CAS
operation with aligned 64bit blocks.
Similarly, in a 64bit machine, one can use the CAS
operation with aligned 128bit blocks.
I'm using a 32bit machine so I tried the following:
// sizeof(long long) is 8 bytes, so 64 bits
long long y = 12;
long long z = 12;
long long x = 99;
__sync_bool_compare_and_swap(&y, z, x);
and the CAS
succeeded changing the value of y
to 99
.
But then I tried using a char array[8];
(which size is 64 bits) instead of a long long
. And I do:
char full[8] = {'0', '1', '2', '3', '4', '5', '6', '7'};
char full2[8] = {'0', '1', '2', '3', '4', '5', '6', '7'};
char full3[8] = {'5', '8', '9', 'G', 'X', '5', '6', 'U'};
__sync_bool_compare_and_swap(full, full2, full3);
But in this case, the CAS
fails although full
and full2
have exactly the same data. (I also checked that full
and full2
where correctly alligned)
So the first time it seems that a CAS
can be used to 64bit, but the second time it seems it can't. Any ideas why?
EDIT
(How about 64bit machines?)
Ok, so the problem was that I was using char *
in my CAS
and these were only checked. So the solution was to cast to long long
or to uint64_t
which are 64bit values.
But what should I do with a 64bit machine when I need to use 128bit value? long long
is still 64bit in a 64bit machine and uint128_t
doesn't seem to exist in C. So to which type should I cast? double long
seems to be 128bit in my 64bit machine, but when doing the following:
double long y = 32432143243214;
double long z = 32432143243214;
int x = __sync_bool_compare_and_swap(&y, z, 1234321990);
I get this compile error
error: incompatible type for argument 1 of ‘__sync_bool_compare_and_swap’
.
Looks like you forgot to deref your pointers and cast.
I tested and this is the only combination that is correct:
__sync_bool_compare_and_swap((long long*)full, *(long long *)full2, *(long long *)full3);
You need to cast the first param or it will only swap the first char.
Regarding handling 128-bit double long, this is from the gcc 4.1.2 docs.
The definition given in the Intel documentation allows only for the use of the types int, long, long long as well as their unsigned counterparts. GCC will allow any integral scalar or pointer type that is 1, 2, 4 or 8 bytes in length.
So it would seem you cannot use this function to handle that case.
You should pass the value of full2 and full3, not a pointer to it. Also, you should be care about the alignment.
__sync_bool_compare_and_swap((long long*)full,*(long long*)full2,*(long long*)full3);
(Of course, this is not portable. If you want portability, use uint64_t
instead of long long
)
You are passing a char *
to __sync_bool_compare_and_swap
. Assuming your char arrays (all three of them!) are properly aligned to 64 bits (if they're allocated in the way you show, they may not be - use malloc
!), try casting to (long long *)
before passing to __sync_bool_compare_and_swap
. Failing that, use inline assembler and invoke CMPXCHG8B
directly.
来源:https://stackoverflow.com/questions/9254082/should-64bit-compareswap-cas-work-on-a-32bit-machine-or-64bit-machine