Define Atomic Operations in Multitasking Code
In code with multiple threads, you can use Polyspace® Bug Finder™ to detect data races or Polyspace Code Prover™ to list potentially unprotected shared variables.
To determine if a variable shared between multiple threads is protected against concurrent access, Polyspace checks if the operations on the variable are atomic.
Nonatomic Operations
If an operation is nonatomic, Polyspace considers that the operation involves multiple steps. These steps do not need to occur together and can be interrupted by operations in other threads.
For instance, consider these two operations in two different threads:
Thread 1:
var++;
This operation is nonatomic because it takes place in three steps: reading
var
, incrementingvar
, and writing backvar
.Thread 2:
var = 0;
This operation is atomic if the size of
var
is less than the word size on the target. See details below for how Polyspace determines the word size.
If the two operations are not protected (by using, for instance, critical
sections), the operation in the second thread can interrupt the operation in the
first thread. If the interruption happens after var
is
incremented in the first thread but before the incremented value is written back,
you can see unexpected results.
What Polyspace Considers as Nonatomic
Code Prover considers all operations as nonatomic unless you protect them, for instance, by using critical sections. See Define Specific Operations as Atomic.
Bug Finder considers an operation as nonatomic if it can translate into more than one machine instruction. For instance:
The operation can involve both a read and write operation. For example,
var++
involves reading the value ofvar
, increasing the value by one and writing the increased value back tovar
.The operation can involve a 64-bit variable on a 32-bit target. For example, the operation
involves two steps in copying the content oflong long var1, var2; var1=var2;
var2
tovar1
on certain targets.Polyspace uses the Pointer size for your Target processor type as the threshold to compute atomicity. For instance, if you use
i386
as your Target processor type, the Pointer size is 32 bits and Long long and Double sizes are both 64 bits. Therefore, Polyspace considers copying onelong long
ordouble
variable to another as nonatomic.See also
Target processor type (-target)
.The operation can involve writing the return value of a function call to a shared variable. For example, the operation
x=func()
involves callingfunc
and writing the return value offunc
tox
.
To detect data races where at least one of the two interrupting operations is nonatomic, enable the Bug Finder checker Data race
. To remove this constraint on the checker, use the option
-detect-atomic-data-race
.
Define Specific Operations as Atomic
You might want to define a group of operations as atomic. This group of operations cannot be interrupted by operations in another thread or task.
Use one of these techniques:
Critical sections
Protect a group of operations with critical sections.
A critical section begins and ends with calls to specific functions. You can use a predefined set of primitives to begin or end critical sections, or use your own functions.
A group of operations in a critical section are atomic with respect to another group of operations that are in the same critical section (that is, having the same beginning and ending function).
Specify critical sections using the option
Critical section details (-critical-section-begin -critical-section-end)
.Temporally exclusive tasks
Protect a group of operations by specifying certain tasks as temporally exclusive.
If a group of tasks are temporally exclusive, all operations in one task are atomic with respect to operations in the other tasks.
Specify temporal exclusion using the option
Temporally exclusive tasks (-temporal-exclusions-file)
.Task priorities
Protect a group of operations by specifying that certain tasks have higher priorities. For instance, interrupts have higher priorities over cyclic tasks.
You can specify up to four different priorities with these options (with highest priority listed first):
All operations in a task with higher priority are atomic with respect to operations in tasks with lower priorities. See also Define Task Priorities for Data Race Detection in Polyspace.
Routine disabling interrupts (Bug Finder only)
Protect a group of operations by disabling all interrupts. Use the option
Disabling all interrupts (-routine-disable-interrupts -routine-enable-interrupts)
.After you call a routine to disable interrupts, all subsequent operations are atomic until you call another routine to reenable interrupts. The operations are atomic with respect to operations in all other tasks.
For a tutorial, see Protections for Shared Variables in Multitasking Code.
See Also
Cyclic tasks
(-cyclic-tasks)
| Interrupts
(-interrupts)
| Critical section
details (-critical-section-begin -critical-section-end)
| Temporally exclusive
tasks (-temporal-exclusions-file)