Giriş
Elimizde şöyle bir kod olsun
Genel kuralın açıklaması şöyle.
Dolayısıyla std::atomic eğer C++20 ile kodlansaydı belki şöyle kodlanabilirdi.
Integral olmayan tipler için kod derlense bile bir yerden sonra hata veriyor.
Örnek - std::atomic<std::string>
Aşağıdaki kod yanlış.
atomic sınıfı aslında bir template. Integral tipler için bir sürü typedef yapılmış. Template olarak kullanmanın bir anlamı yok. Yani şöyle bir kod yazmak anlamsız ancak örneklerde hep bu tür kodlar kullanılıyor.
Yeni bir değer atar, eski değeri döner. While, If gibi koşullarda kullanılabilir.
fetch_add metodu
Açıklaması şöyle.
Açıklaması şöyle
Şöyle yaparız.
Atomic olarak değeri almak veya atamak için kullanılır. Convert operator altta load metodunu kullanırlar.
Örnek - memory_order_acquire
Şöyle yaparız
Şöyle yaparız.
Elimizde bir tane atomic int ve bir const değer olsun.
store metodu - memory order
Örnek
Şöyle yaparı<
Şöyle yaparız.
Açıklaması şöyle.
Şöyle yaparız.
Elimizde şöyle bir kod olsun
int i = 1;
int x = ++i;
Bu kod assembly ile muhtemelen şöyledir. i değişkenine erişim bir çok adımdan oluşur ve multi-threaded ortamda doğru çalışmaz.. 2,3 ve 4 numaraları adımları atomic yapmak mümkün. Bu iş için std::atomic kullanılır. Böylece mutex kullanmdan multi-threaded ortamda da kod doğru çalışır.1. store 1 in i
2. read i as tmp
3. add 1 to tmp
4. store tmp in x
Hangi tipler için kullanabilirizGenel kuralın açıklaması şöyle.
Trivially copyable tipler integral tiplerdir. Integral tiplerden kasıt cstdint dosyasında tanımlı tüm tipler. Bunlar char, signed char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, long long, unsigned long long, char16_t, char32_t, wchar_t vs. olabilir.std::atomic may be instantiated with any TriviallyCopyable type T satisfying both CopyConstructible and CopyAssignable.
Dolayısıyla std::atomic eğer C++20 ile kodlansaydı belki şöyle kodlanabilirdi.
template< class T > requires
std::is_trivially_copyable_v<T> &&
std::is_copy_constructible_v<T> &&
std::is_move_constructible_v<T> &&
std::is_copy_assignable_v<T> &&
std::is_move_assignable_v<T>
struct atomic { ... };
Integral Olmayan TiplerIntegral olmayan tipler için kod derlense bile bir yerden sonra hata veriyor.
Örnek - std::atomic<std::shared_ptr<..>>
std::atomic TriviallyCopyable değil.std::is_trivially_copyable<std::shared_ptr<int>>::value == false;
Ancak std::atomic işlemleri ile çalışması arzu ediliyor. Dolayısıyla bir istisna yapılmış ve std::share_ptr parametresi alan atomic_load(), atomic_store() gibi metodlar tanımlanmış.Aşağıdaki kod yanlış.
#include <atomic>
#include <string>
int main()
{
std::atomic<std::string> a1("127.0.0.1:41001");
std::string ep1_1 = a1.load();
std::string ep1_2 = a1.load();
return 0;
}
Örnek - std::atomic<double>
load ve exchange metodları var. Diğer metodları kendimiz yazmalıyız.
Hazır Typedef'lerstd::atomic<double> foo{0};
void add_to_foo(double bar) {
auto current = foo.load();
while (!foo.compare_exchange_weak(current, current + bar))
;
}
Örnek - std::atomic<std::array<..>>
Bu kod std::is_trivially_copyable için true dönüyor. Ancak yapmayın çünkü performansı öldürür.
Bu kod std::is_trivially_copyable için true dönüyor. Ancak yapmayın çünkü performansı öldürür.
std::atomic<std::array<int,10>> myArray;
Açıklaması şöyle.The power of atomic variables come from the fact that some processors can do their operations with one instruction. The C++ compiler will try to make your atomic operations happen in one instruction. If it fails, it'll initiate a bus lock, which is like a global lock of everything, until that array is updated. It's equivalent to a mutex that locks all your variables in your program. If you're concerned about performance, don't do that!
atomic sınıfı aslında bir template. Integral tipler için bir sürü typedef yapılmış. Template olarak kullanmanın bir anlamı yok. Yani şöyle bir kod yazmak anlamsız ancak örneklerde hep bu tür kodlar kullanılıyor.
std::atomic<bool>
- std::atomic_int
- std::atomic_uint,
- std::atomic_llong,
- std::atomic_bool
yazılarına bakabilirsiniz.
compare_exchange_weak metodu
Şöyle yaparız.- std::atomic_uint,
- std::atomic_llong,
- std::atomic_bool
yazılarına bakabilirsiniz.
compare_exchange_weak metodu
// Effect: x += n, returns old value of x.
int inc(int n, std::atomic<int> & x)
{
int old_val = x.load();
for (;;) {
int new_val = old_val + n;
if (x.compare_exchange_weak(old_val, new_val)) {
return old_val;
}
// Note: If the exchange fails, old_val is updated
// to the current value of x.
}
}
exchange metoduYeni bir değer atar, eski değeri döner. While, If gibi koşullarda kullanılabilir.
fetch_add metodu
Açıklaması şöyle.
Şöyle yaparız.Atomically replaces the current value with the result of arithmetic addition of the value and arg. The operation is read-modify-write operation. Memory is affected according to the value of order.
std::atomic<int> num;
num.fetch_add (1, std::memory_order_relaxed);
fetch_sub metoduAçıklaması şöyle
A fetch_sub operation with memory_order_acquire semantics doesn’t synchronize-with anything, even though it stores a value, because it isn’t a release operation. Likewise, a store can’t synchronize-with a fetch_or with memory_order_release semantics, because the read part of the fetch_or isn’t an acquire operation.is_lock_free metodu
Şöyle yaparız.
std::atomic<foo> var;
std::cout << var.is_lock_free() << std::endl;
std::cout << sizeof(var) << std::endl;
Çıktı olarak şunu alırız.0
16
load metoduAtomic olarak değeri almak veya atamak için kullanılır. Convert operator altta load metodunu kullanırlar.
load metodu - memory orderAssignment and access operations are atomic
Örnek - memory_order_acquire
Şöyle yaparız
std::atomic<bool> x;
while (x.load(std::memory_order_acquire) == false)
{
x.wait(false, std::memory_order_acquire);
}
Örnek - memory_order_relaxedŞöyle yaparız.
atomic<int> x(0);
x.store(1,std::memory_order_relaxed);
while(!x.load(memory_order_relaxed)) {...}
operator ++ metodu - pre incrementElimizde bir tane atomic int ve bir const değer olsun.
std::atomic<int> a = 10;
int i = 20;
Belli bir sınırı geçince işlem yapmak istersek şöyle yaparız.if( ++a > i )
{
// a is still not guaranteed to be greater than i at this point,
// but AT THE TIME OF INCREMENTING it did exceed i.
}
Bu metod altta şu çağrıyı yapar.
Şöyle yaparız.
Assignment operator altta store metodunu kullanırlar.fetch_add(1);
operator -- metodu - pre decrementŞöyle yaparız.
std::atomic<int> value(0);
--value;
store metodustore metodu - memory order
Örnek
Şöyle yaparı<
std::atomic<int> flag { 0 };
void writer_thread() {
// release value x to reader thread
flag.store(1, std::memory_order_release);
}
ÖrnekŞöyle yaparız.
std::atomic<int> y(0);
void f() {
auto order = std::memory_order_relaxed;
y.store(1, order);
...
}
wait metoduAçıklaması şöyle.
According to cppreference, in C++20 there are wait, notify_one, notify_all in std::atomic<T>. Looks like they make std::atomic<T> usable as a futex.Örnek
Şöyle yaparız.
std::atomic<bool> x;
while (x.load(std::memory_order_acquire) == false)
{
x.wait(false, std::memory_order_acquire);
}
Hiç yorum yok:
Yorum Gönder