[Date: 2011-06-17] |
Source: Linux community Author: franktan |
GCC provides the _ sync _ * series of built-in functions from 4.1.2 to provide atomic operations for addition and subtraction and logical operations.
The statement is as follows:
--> Type _ sync_fetch_and_add (type * PTR, type value ,...)
Type _ sync_fetch_and_sub (type * PTR, type value ,...)
Type _ sync_fetch_and_or (type * PTR, type value ,...)
Type _ sync_fetch_and_and (type * PTR, type value ,...)
Type _ sync_fetch_and_xor (type * PTR, type value ,...)
Type _ sync_fetch_and_nand (type * PTR, type value ,...)
Type _ sync_add_and_fetch (type * PTR, type value ,...)
Type _ sync_sub_and_fetch (type * PTR, type value ,...)
Type _ sync_or_and_fetch (type * PTR, type value ,...)
Type _ sync_and_and_fetch (type * PTR, type value ,...)
Type _ sync_xor_and_fetch (type * PTR, type value ,...)
Type _ sync_nand_and_fetch (type * PTR, type value ,...)
The difference between the two groups of functions is that the first group returns the value before the update, and the second group returns the updated value.
Type can be 1, 2, 4, or 8-byte int type, that is:
Int8_t/uint8_t
Int16_t/uint16_t
Int32_t/uint32_t
Int64_t/uint64_t
The following extensible parameters (...) it is used to indicate which variables need memory barrier, because GCC currently implements full Barrier (similar to the MB () in Linux kernel (), indicates that all memory operations prior to this operation will not be reordered to this operation), so this parameter can be omitted.
Bool _ sync_bool_compare_and_swap (type * PTR, type oldval type newval ,...)
Type _ sync_val_compare_and_swap (type * PTR, type oldval type newval ,...)
These two functions provide atomic comparison and exchange. If * PTR = oldval, newval is written to * PTR,
The first function returns true if it is equal and written.
The value of the second function before the return operation.
_ Sync_synchronize (...)
Sends out a full Barrier.
With regard to memory barrier, the CPU sorts our commands, which generally improves program efficiency, but sometimes results in undesirable results. For example, for example, we have a hardware device with four registers. When you issue an operation command, one register stores your operation command (such as read ), the two registers store parameters (such as address and size), and the last register is the control register. After all the parameters are set, it sends a command to the device to start reading the parameters, run the following command: write1 (Dev. register_size, size );
Write1 (Dev. register_addr, ADDR );
Write1 (Dev. register_cmd, read );
Write1 (Dev. register_control, go );
If the last write1 is replaced with the first few statements, it is definitely not what we expected. In this case, we can add a memory barrier before the last statement, force the CPU to execute the previous write before executing the last one:
Write1 (Dev. register_size, size );
Write1 (Dev. register_addr, ADDR );
Write1 (Dev. register_cmd, read );
_ Sync_synchronize ();
Write1 (Dev. register_control, go );
Memory barrier has several types:
Acquire barrier: it is not allowed to move the memory READ command after barrier to barrier (WMB () in Linux kernel ()).
Release barrier: it is not allowed to move the memory read commands before barriers to barriers (RMB () in Linux kernel ()).
Full barrier: a collection of the preceding two barrier types (MB () in Linux kernel ()).
There are two other functions:
Type _ sync_lock_test_and_set (type * PTR, type value ,...)
Set * PTR to value and return the value before * PTR operation.
Void _ sync_lock_release (type * PTR ,...)
Set * PTR to 0
Example program:
# Include <stdio. h>
# Include <pthread. h>
# Include <stdlib. h>
Static int COUNT = 0;
Void * test_func (void * Arg)
{
Int I = 0;
For (I = 0; I <20000; ++ I ){
_ Sync_fetch_and_add (& count, 1 );
}
Return NULL;
}
Int main (INT argc, const char * argv [])
{
Pthread_t ID [20];
Int I = 0;
For (I = 0; I <20; ++ I ){
Pthread_create (& ID [I], null, test_func, null );
}
For (I = 0; I <20; ++ I ){
Pthread_join (ID [I], null );
}
Printf ("% d/N", count );
Return 0;
}