xtd - Reference Guide 0.2.0
xtd::threading::interlocked Class Reference

#include <interlocked.h>

Definition

Provides atomic operations for variables that are shared by multiple threads.

class core_export_ interlocked static_
Inheritance
xtd::static_objectxtd::threading::interlocked
Namespace
xtd
Library
xtd.core
Remarks
The methods of this class help protect against errors that can occur when the scheduler switches contexts while a thread is updating a variable that can be accessed by other threads, or when two threads are executing concurrently on separate processors. The members of this class do not throw exceptions.
The xtd::threading::interlocked::increment and xtd::threading::interlocked::decrement methods increment or decrement a variable and store the resulting value in a single operation. On most computers, incrementing a variable is not an atomic operation, requiring the following steps:
1. Load a value from an instance variable into a register.
2. Increment or decrement the value.
3. Store the value in the instance variable.
If you do not use xtd::threading::interlocked::increment and xtd::threading::interlocked::decrement, a thread can be preempted after executing the first two steps. Another thread can then execute all three steps. When the first thread resumes execution, it overwrites the value in the instance variable, and the effect of the increment or decrement performed by the second thread is lost.
The xtd::threading::exchange method atomically exchanges the values of the specified variables. The compare_exchange method combines two operations: comparing two values and storing a third value in one of the variables, based on the outcome of the comparison. The compare and exchange operations are performed as an atomic operation.
Examples
The following code example shows a thread-safe resource locking mechanism.
#include <vector>
#include <thread>
#include <xtd/xtd>
using namespace std;
using namespace std::chrono;
using namespace xtd;
using namespace xtd::threading;
namespace examples {
struct my_thread {
std::thread thread;
ustring name;
};
class my_interlocked_exchange_class : public object {
private:
//0 for False, 1 for True.
inline static int using_resource = 0;
static const int num_thread_iterations = 5;
static const int num_threads = 10;
public:
// The main entry point for the application.
static void main() {
vector<my_thread> my_threads(num_threads);
for (int i = 0; i < num_threads; ++i) {
my_threads[i].name = ustring::format("Thread{0}", i + 1);
//Wait a random amount of time before starting next thread.
this_thread::sleep_for(milliseconds(rnd.next(0, 1000)));
my_threads[i].thread = thread(my_thread_proc, my_threads[i].name);
}
for (int i = 0; i < num_threads; ++i)
my_threads[i].thread.join();
}
static void my_thread_proc(const ustring& name) {
for (int i = 0; i < num_thread_iterations; i++) {
use_resource(name);
//Wait 1 second before next attempt.
this_thread::sleep_for(milliseconds(1000));
}
}
//A simple method that denies reentrancy.
static bool use_resource(const ustring& name) {
//0 indicates that the method is not in use.
if (0 == interlocked::exchange(using_resource, 1)) {
console::write_line("{0} acquired the lock", name);
//Code to access a resource that is not thread safe would go here.
//Simulate some work
this_thread::sleep_for(milliseconds(500));
console::write_line("{0} exiting lock", name);
//Release the lock
interlocked::exchange(using_resource, 0);
return true;
} else {
console::write_line(" {0} was denied the lock", name);
return false;
}
}
};
}
startup_(examples::my_interlocked_exchange_class);

Static Public Member Functions

static int32_t add (int32_t &location, int32_t value) noexcept
 Adds two 32-bit integers and replaces the first integer with the sum, as an atomic operation. More...
 
static int64_t add (int64_t &location, int64_t value) noexcept
 Adds two 64-bit integers and replaces the first integer with the sum, as an atomic operation. More...
 
static double compare_exchange (double &location, double value, double comparand) noexcept
 Compares two Double for equality and, if they are equal, replaces one of the values. More...
 
static int32_t compare_exchange (int32_t &location, int32_t value, int32_t comparand) noexcept
 Compares two 32-bit signed integers for equality and, if they are equal, replaces one of the values. More...
 
static int64_t compare_exchange (int64_t &location, int64_t value, int64_t comparand) noexcept
 Compares two 64-bit signed integers for equality and, if they are equal, replaces one of the values. More...
 
static void * compare_exchange (void *&location, void *value, void *comparand) noexcept
 Compares two platform-specific handles or pointers for equality and, if they are equal, replaces one of them. More...
 
template<typename type_t >
static type_t compare_exchange (object &location, const object &value, const object &comparand) noexcept
 Compares two objects for equality and, if they are equal, replaces one of them. More...
 
template<typename type_t >
static type_t compare_exchange (type_t &location, type_t value, type_t comparand) noexcept
 Compares two instances of the specified reference type type_t for equality and, if they are equal, replaces one of them. More...
 
static float compare_exchange (float &location, float value, float comparand) noexcept
 Compares two Single for equality and, if they are equal, replaces one of the values. More...
 
static int32_t decrement (int32_t &location) noexcept
 Decrements a specified variable and stores the result, as an atomic operation. More...
 
static int64_t decrement (int64_t &location) noexcept
 Decrements a specified variable and stores the result, as an atomic operation. More...
 
template<typename type_t >
static type_t exchange (type_t &location, type_t value)
 Sets a variable of the specified type type_t to a specified value and returns the original value, as an atomic operation. More...
 
static double exchange (double &location, double value) noexcept
 Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation. More...
 
static int32_t exchange (int32_t &location, int32_t value) noexcept
 Sets a 32-bit signed integer to a specified value and returns the original value, as an atomic operation. More...
 
static int64_t exchange (int64_t &location, int64_t value) noexcept
 Sets a 64-bit signed integer to a specified value and returns the original value, as an atomic operation. More...
 
static void * exchange (void *&location, void *value) noexcept
 Sets a platform-specific handles or pointers to a specified value and returns the original value, as an atomic operation. More...
 
template<typename type_t >
static type_t exchange (object &location, const object &value) noexcept
 Sets an object to a specified value and returns the original value, as an atomic operation. More...
 
static float exchange (float &location, float value) noexcept
 Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation. More...
 
static int32_t increment (int32_t &location) noexcept
 Increments a specified variable and stores the result, as an atomic operation. More...
 
static int64_t increment (int64_t &location) noexcept
 Increments a specified variable and stores the result, as an atomic operation. More...
 
static void memory_barrier () noexcept
 Synchronizes memory access as follows: The processor that executes the current thread cannot reorder instructions in such a way that memory accesses before the call to xtd::threading::interlocked::memory_barrier execute after memory accesses that follow the call to xtd::threading::interlocked::memory_barrier. More...
 
static int64_t read (int64_t &location) noexcept
 Returns a 64-bit value, loaded as an atomic operation. More...
 

Member Function Documentation

◆ add() [1/2]

static int32_t xtd::threading::interlocked::add ( int32_t &  location,
int32_t  value 
)
staticnoexcept

Adds two 32-bit integers and replaces the first integer with the sum, as an atomic operation.

Parameters
locationA variable containing the first value to be added. The sum of the two values is stored in location.
valueThe value to be added to the integer at location.
Returns
int32_t The new value stored at location.

◆ add() [2/2]

static int64_t xtd::threading::interlocked::add ( int64_t &  location,
int64_t  value 
)
staticnoexcept

Adds two 64-bit integers and replaces the first integer with the sum, as an atomic operation.

Parameters
locationA variable containing the first value to be added. The sum of the two values is stored in location.
valueThe value to be added to the integer at location.
Returns
int64_t The new value stored at location.

◆ compare_exchange() [1/7]

static double xtd::threading::interlocked::compare_exchange ( double &  location,
double  value,
double  comparand 
)
staticnoexcept

Compares two Double for equality and, if they are equal, replaces one of the values.

Parameters
locationThe destination, whose value is compared with comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
comparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ compare_exchange() [2/7]

static int32_t xtd::threading::interlocked::compare_exchange ( int32_t &  location,
int32_t  value,
int32_t  comparand 
)
staticnoexcept

Compares two 32-bit signed integers for equality and, if they are equal, replaces one of the values.

Parameters
locationThe destination, whose value is compared with Comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
ComparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ compare_exchange() [3/7]

static int64_t xtd::threading::interlocked::compare_exchange ( int64_t &  location,
int64_t  value,
int64_t  comparand 
)
staticnoexcept

Compares two 64-bit signed integers for equality and, if they are equal, replaces one of the values.

Parameters
locationThe destination, whose value is compared with comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
comparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ compare_exchange() [4/7]

static void* xtd::threading::interlocked::compare_exchange ( void *&  location,
void *  value,
void *  comparand 
)
staticnoexcept

Compares two platform-specific handles or pointers for equality and, if they are equal, replaces one of them.

Parameters
locationThe destination, whose value is compared with comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
comparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ compare_exchange() [5/7]

template<typename type_t >
static type_t xtd::threading::interlocked::compare_exchange ( object location,
const object value,
const object comparand 
)
inlinestaticnoexcept

Compares two objects for equality and, if they are equal, replaces one of them.

Parameters
locationThe destination, whose value is compared with comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
comparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ compare_exchange() [6/7]

template<typename type_t >
static type_t xtd::threading::interlocked::compare_exchange ( type_t &  location,
type_t  value,
type_t  comparand 
)
inlinestaticnoexcept

Compares two instances of the specified reference type type_t for equality and, if they are equal, replaces one of them.

Parameters
locationThe destination, whose value is compared with comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
comparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ compare_exchange() [7/7]

static float xtd::threading::interlocked::compare_exchange ( float &  location,
float  value,
float  comparand 
)
staticnoexcept

Compares two Single for equality and, if they are equal, replaces one of the values.

Parameters
locationThe destination, whose value is compared with comparand and possibly replaced.
valueThe value that replaces the destination value if the comparison results in equality.
comparandThe value that is compared to the value at location.
Returns
The original value in location.

◆ decrement() [1/2]

static int32_t xtd::threading::interlocked::decrement ( int32_t &  location)
staticnoexcept

Decrements a specified variable and stores the result, as an atomic operation.

Parameters
locationThe variable whose value is to be decremented.
Returns
The decremented value.
Examples
The following code example shows a thread-safe way to increment and decrement an integer value. SafeInstanceCount will always be zero. However, UnsafeInstanceCount will not necessarily be zero because a race condition occurs between incrementing and decrementing the count. This effect is especially marked on a multiprocessor computer.
#include <vector>
#include <thread>
#include <xtd/xtd>
using namespace std;
using namespace xtd;
using namespace xtd::threading;
namespace examples {
class my_interlocked_decrement_class {
private:
class count_class : public object {
public:
inline static int unsafe_instance_count = 0;
inline static int safe_instance_count = 0;
count_class() {
unsafe_instance_count++;
interlocked::increment(safe_instance_count);
}
~count_class() {
unsafe_instance_count--;
interlocked::decrement(safe_instance_count);
}
};
public:
static void main() {
thread thread1(thread_method);
thread thread2(thread_method);
thread1.join();
thread2.join();
console::write_line("unsafe_instance_count: {}\nsafe_instance_count: {}", count_class::unsafe_instance_count, count_class::safe_instance_count);
}
private:
static void thread_method() {
unique_ptr<count_class> cc;
// Create 100000 instances of count_class.
for (int i = 0; i < 100000; ++i)
cc = make_unique<count_class>();
}
};
}
startup_(examples::my_interlocked_decrement_class);
// This code produces the following output:
//
// unsafe_instance_count: 27401
// safe_instance_count: 0

◆ decrement() [2/2]

static int64_t xtd::threading::interlocked::decrement ( int64_t &  location)
staticnoexcept

Decrements a specified variable and stores the result, as an atomic operation.

Parameters
locationThe variable whose value is to be decremented.
Returns
The decremented value.

◆ exchange() [1/7]

template<typename type_t >
static type_t xtd::threading::interlocked::exchange ( type_t &  location,
type_t  value 
)
inlinestatic

Sets a variable of the specified type type_t to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location parameter is set.
Returns
The original value of location.

◆ exchange() [2/7]

static double xtd::threading::interlocked::exchange ( double &  location,
double  value 
)
staticnoexcept

Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location_d parameter is set.
Returns
The original value of location_d.

◆ exchange() [3/7]

static int32_t xtd::threading::interlocked::exchange ( int32_t &  location,
int32_t  value 
)
staticnoexcept

Sets a 32-bit signed integer to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location parameter is set.
Returns
The original value of location.
Examples
The following code example shows a thread-safe resource locking mechanism.
#include <vector>
#include <thread>
#include <xtd/xtd>
using namespace std;
using namespace std::chrono;
using namespace xtd;
using namespace xtd::threading;
namespace examples {
struct my_thread {
std::thread thread;
ustring name;
};
class my_interlocked_exchange_class : public object {
private:
//0 for False, 1 for True.
inline static int using_resource = 0;
static const int num_thread_iterations = 5;
static const int num_threads = 10;
public:
// The main entry point for the application.
static void main() {
vector<my_thread> my_threads(num_threads);
for (int i = 0; i < num_threads; ++i) {
my_threads[i].name = ustring::format("Thread{0}", i + 1);
//Wait a random amount of time before starting next thread.
this_thread::sleep_for(milliseconds(rnd.next(0, 1000)));
my_threads[i].thread = thread(my_thread_proc, my_threads[i].name);
}
for (int i = 0; i < num_threads; ++i)
my_threads[i].thread.join();
}
static void my_thread_proc(const ustring& name) {
for (int i = 0; i < num_thread_iterations; i++) {
use_resource(name);
//Wait 1 second before next attempt.
this_thread::sleep_for(milliseconds(1000));
}
}
//A simple method that denies reentrancy.
static bool use_resource(const ustring& name) {
//0 indicates that the method is not in use.
if (0 == interlocked::exchange(using_resource, 1)) {
console::write_line("{0} acquired the lock", name);
//Code to access a resource that is not thread safe would go here.
//Simulate some work
this_thread::sleep_for(milliseconds(500));
console::write_line("{0} exiting lock", name);
//Release the lock
interlocked::exchange(using_resource, 0);
return true;
} else {
console::write_line(" {0} was denied the lock", name);
return false;
}
}
};
}
startup_(examples::my_interlocked_exchange_class);

◆ exchange() [4/7]

static int64_t xtd::threading::interlocked::exchange ( int64_t &  location,
int64_t  value 
)
staticnoexcept

Sets a 64-bit signed integer to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location parameter is set.
Returns
The original value of location.

◆ exchange() [5/7]

static void* xtd::threading::interlocked::exchange ( void *&  location,
void *  value 
)
staticnoexcept

Sets a platform-specific handles or pointers to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location parameter is set.
Returns
The original value of location.

◆ exchange() [6/7]

template<typename type_t >
static type_t xtd::threading::interlocked::exchange ( object location,
const object value 
)
inlinestaticnoexcept

Sets an object to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location parameter is set.
Returns
The original value of location.

◆ exchange() [7/7]

static float xtd::threading::interlocked::exchange ( float &  location,
float  value 
)
staticnoexcept

Sets a double-precision floating point number to a specified value and returns the original value, as an atomic operation.

Parameters
locationThe variable to set to the specified value.
valueThe value to which the location_f parameter is set.
Returns
The original value of location_f.

◆ increment() [1/2]

static int32_t xtd::threading::interlocked::increment ( int32_t &  location)
staticnoexcept

Increments a specified variable and stores the result, as an atomic operation.

Parameters
locationThe variable whose value is to be incremented.
Returns
The incremented value.
Examples
The following code example shows a thread-safe way to increment and decrement an integer value. SafeInstanceCount will always be zero. However, UnsafeInstanceCount will not necessarily be zero because a race condition occurs between incrementing and decrementing the count. This effect is especially marked on a multiprocessor computer.
#include <vector>
#include <thread>
#include <xtd/xtd>
using namespace std;
using namespace xtd;
using namespace xtd::threading;
namespace examples {
class my_interlocked_decrement_class {
private:
class count_class : public object {
public:
inline static int unsafe_instance_count = 0;
inline static int safe_instance_count = 0;
count_class() {
unsafe_instance_count++;
interlocked::increment(safe_instance_count);
}
~count_class() {
unsafe_instance_count--;
interlocked::decrement(safe_instance_count);
}
};
public:
static void main() {
thread thread1(thread_method);
thread thread2(thread_method);
thread1.join();
thread2.join();
console::write_line("unsafe_instance_count: {}\nsafe_instance_count: {}", count_class::unsafe_instance_count, count_class::safe_instance_count);
}
private:
static void thread_method() {
unique_ptr<count_class> cc;
// Create 100000 instances of count_class.
for (int i = 0; i < 100000; ++i)
cc = make_unique<count_class>();
}
};
}
startup_(examples::my_interlocked_decrement_class);
// This code produces the following output:
//
// unsafe_instance_count: 27401
// safe_instance_count: 0

◆ increment() [2/2]

static int64_t xtd::threading::interlocked::increment ( int64_t &  location)
staticnoexcept

Increments a specified variable and stores the result, as an atomic operation.

Parameters
locationThe variable whose value is to be incremented.
Returns
The incremented value.

◆ memory_barrier()

static void xtd::threading::interlocked::memory_barrier ( )
staticnoexcept

Synchronizes memory access as follows: The processor that executes the current thread cannot reorder instructions in such a way that memory accesses before the call to xtd::threading::interlocked::memory_barrier execute after memory accesses that follow the call to xtd::threading::interlocked::memory_barrier.

Remarks
This method was added to the xtd::threading::interlocked class as a convenience; it's a wrapper for the xtd::threading::thread::memory_barrier method.
xtd::threading::interlocked::memory_barrier is required only on multiprocessor systems that have weak memory ordering (for example, a system that employs multiple Intel Itanium processors).
For most purposes, the lock_ statement, or the Monitor class provide easier ways to synchronize data.

◆ read()

static int64_t xtd::threading::interlocked::read ( int64_t &  location)
staticnoexcept

Returns a 64-bit value, loaded as an atomic operation.

Parameters
locationThe 64-bit value to be loaded.
Returns
The loaded value.

The documentation for this class was generated from the following file: