[Concurrency] Atomic Operation: Memory Fence์™€ Memory Ordering

์ด ํฌ์ŠคํŠธ๋Š” atomic ์—ฐ์‚ฐ์—์„œ ๊ณ ๋ คํ•ด์•ผํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ˆœ์„œ์— ๋Œ€ํ•ด ๋‹ค๋ฃฌ๋‹ค.
์˜ˆ์‹œ ์ฝ”๋“œ๋Š” Rust์ง€๋งŒ, Rust๋ฅผ ๋ชฐ๋ผ๋„ ๋‚ด์šฉ์€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

๋ฉ”๋ชจ๋ฆฌ ํŽœ์Šค(Fence)์™€ ์ˆœ์„œ(Ordering)๋Š” Atomic operation ๊ธฐ๋ฐ˜์˜ ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌ์— ์žˆ์–ด์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํ•ต์‹ฌ ์š”์†Œ๋‹ค. ์ด๊ฑธ ์ œ๋Œ€๋กœ ์•Œ์ง€ ๋ชปํ•˜๊ณ  ์“ด๋‹ค๋ฉด Atomic์„ ์“ฐ๋Š” ์˜๋ฏธ๊ฐ€ ์ „ํ˜€ ์—†๋‹ค.




Out Of Order ํ˜„์ƒ

fence๋ผ๋Š” ๊ฒƒ์ด ์™œ ํ•„์š”ํ•œ์ง€๋ฅผ ์•Œ๋ ค๋ฉด, CPU์˜ ๊ตฌ์กฐ์™€ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•œ๋‹ค.
ํ˜„๋Œ€์˜ ์ปดํŒŒ์ผ๋Ÿฌ๋“ค์€ ํ•„์ˆ˜์ ์œผ๋กœ ์ธ์ŠคํŠธ๋Ÿญ์…˜ ์ˆ˜์ค€์˜ ๋น ๋ฅธ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ํŒŒ์ดํ”„๋ผ์ด๋‹(Pipelining)์ด๋ผ๋Š” ์ตœ์ ํ™”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋ ค๋ฉด ์ธ์ŠคํŠธ๋Ÿญ์…˜๋“ค์„ ๋น ๋ฅด๊ฒŒ ๋ณ‘๋ ฌ๋กœ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•ด์„œ ๋ช…๋ น์–ด์˜ ์ˆœ์„œ๋ฅผ ๋งˆ์Œ๋Œ€๋กœ ์กฐ์ž‘ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

๋งŒ์•ฝ ์ฝ”๋“œ๊ฐ€ ๋‹ค์Œ์˜ ์ˆœ์„œ๋กœ ์ •์˜๋˜์—ˆ๋”๋ผ๋„

  1. C = A+B

  2. X = Y+Z



์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ด๊ฑธ ๋’ค์ง‘์–ด๋ฒ„๋ฆด ์ˆ˜๋„ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

  1. X = Y+Z

  2. C = A+B



์ด๊ฑด ์‹ฑ๊ธ€์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ, ๋™์‹œ์„ฑ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋œ๋‹ค.

ํŒŒ์ดํ”„๋ผ์ด๋‹ ์™ธ์—๋„ ์ปดํŒŒ์ผ๋Ÿฌ๋‚˜ ํ•˜๋“œ์›จ์–ด ์ˆ˜์ค€ ์ตœ์ ํ™”์—์„œ ์ด๋ ‡๊ฒŒ ์ˆœ์„œ๋ฅผ ๊ผฌ์•„๋†“๋Š” ์›์ธ์€ ๋ช‡๊ฐ€์ง€ ๋” ์žˆ๋‹ค.




Memory Fence

๊ทธ๋ž˜์„œ ์ €๋ ‡๊ฒŒ ์ˆœ์„œ๊ฐ€ ๋ง๊ฐ€์ง€๋Š” ์ƒํ™ฉ ์†์—์„œ ์ตœ์†Œํ•œ์˜ ์•ˆ์ „์žฅ์น˜๋ฅผ ๋งˆ๋ จํ•˜๋Š” ๊ฒƒ์„ ๋ฉ”๋ชจ๋ฆฌ ํŽœ์Šค๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
Arm์—์„œ๋Š” ์ด๊ฑธ Memory Barrier๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

x86์—์„œ๋Š” sfence/mfence/lfence์™€ ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ , ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์„œ๋“ค๋„ ๋…์ž์ ์ธ ์ผ๋ จ์˜ ๋ช…๋ น์–ด๋กœ ์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์ ์€, ๊ณ ๊ธ‰ ์–ธ์–ด์—์„œ atomic ์—ฐ์‚ฐ๋“ค์„ ๋‹ค๋ฃฐ ๋•Œ์—๋„ ์ด๋Ÿฌํ•œ ๊ฐœ๋…์„ ์–ด๋А์ •๋„ ์•Œ๊ณ  ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
๋Œ€๋‹ค์ˆ˜์˜ ์ถ”์ƒํ™”๋œ atomic operation ํ•จ์ˆ˜๋“ค์€, Ordering์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€๋ฅผ ์ง€์ •ํ•˜๋„๋ก ๋˜์–ด์žˆ๋‹ค.

Ordering ์˜ต์…˜์€ ์–ธ์–ด๋ฅผ ๋ถˆ๋ฌธํ•˜๊ณ  ๋ณดํ†ต ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ •์˜๋œ๋‹ค.

  1. Relaxed: ์•„๋ฌด ์ œ์•ฝ ์—†์Œ
  2. Acquire: ์ด ๋ช…๋ น ์ดํ›„์— ์„ ์–ธ๋œ read๊ฐ€ ์ ˆ๋Œ€ ์ด ๋ช…๋ น ์ด์ „์— ์‹คํ–‰๋˜์ง€ ์•Š์Œ.
  3. Release: ์ด ๋ช…๋ น ์ด์ „์— ์„ ์–ธ๋œ write๊ฐ€ ์ ˆ๋Œ€ ์ด ๋ช…๋ น ์ดํ›„์— ์‹คํ–‰๋˜์ง€ ์•Š์Œ.
  4. AcqRel: ์ฝ๊ธฐ๋Š” Acquire, ์“ฐ๊ธฐ๋Š” Release๋กœ ์ฒ˜๋ฆฌ
  5. SecCst: ์ด ๋ช…๋ น ์•ž๋’ค์˜ read/write ๋ช…๋ น์˜ ์ˆœ์„œ๋ฅผ ์—„๊ฒฉํ•˜๊ฒŒ ์•ž๋’ค ๊ทธ๋Œ€๋กœ ์œ ์ง€

๊ทธ๋ž˜์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ atomic์œผ๋กœ ๋™์‹œ์— ์ฝ๊ณ  ์“ฐ๋Š” ์ž‘์—…์„ ํ• ๋•Œ๋Š” Acquire, ์“ฐ๊ธฐ ์ž‘์—…์„ ํ• ๋•Œ๋Š” Release๋ฅผ ์จ์„œ ์ธ์ŠคํŠธ๋Ÿญ์…˜ ์ˆœ์„œ๊ฐ€ ๊ผฌ์ด์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ๊ธฐ๋ณธ์ด๋‹ค.
ํ•˜์ง€๋งŒ ๊ฐ atomic์ด ๋…๋ฆฝ์ ์ด๊ณ  ์„œ๋กœ ์ฐธ์กฐ๊ด€๊ณ„๊ฐ€ ์—†๋‹ค๋ฉด Relaxed๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ๋น ๋ฅด๋‹ค.

SecCst๋Š” ๊ฐ€์žฅ ์—„๊ฒฉํ•œ Ordering์ธ๋ฐ, ์ด๊ฑธ ์จ์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์˜จ๋‹ค๋ฉด ๋ญ”๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ž˜๋ชป ์ง ๊ฒŒ ์•„๋‹Œ์ง€๋ฅผ ๋จผ์ € ๊ณ ๋ฏผํ•ด๋ด์•ผ ํ•œ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ๋Š” ์ด๊ฑธ ์‚ฌ์šฉํ•  ์ผ์ด ๊ฑฐ์˜ ์—†๊ณ , ์“ฐ๋”๋ผ๋„ Atomic์„ ์“ฐ๋Š” ์˜๋ฏธ๊ฐ€ ์—†๋‹ค.

ํ•œ๋ฒˆ ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ๋™์ž‘ ์›๋ฆฌ์™€ ํ•„์š”์„ฑ์„ ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•ด๋ณด๊ฒ ๋‹ค.




Relaxed Ordering

Relaxed Ordering์€ ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ์˜ memory ordering์ด๋‹ค. ๋‹จ์ˆœํžˆ ์—ฐ์‚ฐ์ด atomicํ•˜๊ฒŒ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ๋งŒ์ด ๋ณด์žฅ๋œ๋‹ค. ๋‹จ์ˆœํ•œ ๋งŒํผ ๋น ๋ฅด์ง€๋งŒ, ์—ฌ๋Ÿฌ๊ฐœ์˜ atomic operation์ด ์žˆ์„ ๋•Œ ๊ทธ ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ฒ ๋‹ค.

use std::sync::{atomic::AtomicI64, Arc};

fn main() {
    let x = Arc::new(AtomicI64::new(0));
    let y = Arc::new(AtomicI64::new(0));

    let thread1 = {
        let x = x.clone();
        let y = y.clone();
        std::thread::spawn(move || {
            let y_value = y.load(std::sync::atomic::Ordering::Relaxed);
            x.store(y_value, std::sync::atomic::Ordering::Relaxed);

            println!("y_value = {}", y_value);
        })
    };

    let thread2 = {
        let x = x.clone();
        let y = y.clone();
        std::thread::spawn(move || {
            let x_value = x.load(std::sync::atomic::Ordering::Relaxed);
            y.store(4444, std::sync::atomic::Ordering::Relaxed);

            println!("x_value = {}", x_value);
        })
    };

    thread1.join().unwrap();
    thread2.join().unwrap();
}

x์™€ y์˜ ์ดˆ๊ธฐ๊ฐ’์€ 0์ด๋‹ค.
์ฒซ๋ฒˆ์จฐ ์Šค๋ ˆ๋“œ์—์„œ๋Š” y์˜ ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ x์— ํ• ๋‹นํ•˜๊ณ 
๋‘๋ฒˆ์งธ ์Šค๋ ˆ๋“œ์—์„œ๋Š” x์˜ ๊ฐ’์„ ๊ฐ€์ ธ์˜ค์ง€๋งŒ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š๊ณ , y์— 4444๋ผ๋Š” ์ˆซ์ž๊ฐ’์„ ํ• ๋‹นํ•œ๋‹ค.

์ด๊ฑด ์‹ค์ œ ์Šค๋ ˆ๋“œ ์‹คํ–‰ ์ˆœ์„œ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ, x_value ๋ณ€์ˆ˜๋Š” ๋ณดํ†ต 0 ๊ฐ’์„ ๊ฐ€์งˆ ๊ฒƒ์ด๋ผ ๊ธฐ๋Œ€ํ•  ๊ฒƒ์ด๋‹ค.
์™œ๋ƒํ•˜๋ฉด x ๊ฐ’์€ y ๊ฐ’์— ์˜์กด์ ์ธ๋ฐ, ๋‘๋ฒˆ์งธ ์Šค๋ ˆ๋“œ์—์„œ๋Š” x ๊ฐ’์„ ๋จผ์ € ๊ฐ€์ ธ์˜จ ๋‹ค์Œ์— y์— ๊ฐ’์„ ํ• ๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ, Relaxed Ordering์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” x_value๊ฐ€ 4444๋ฅผ ๊ฐ€์ง€๋Š” ์ด์ƒํ•œ ์ƒํ™ฉ์ด ์ƒ๊ธธ ์ˆ˜๋„ ์žˆ๋‹ค.

Relaxed Ordering์˜ ์‹ค์ œ ๋™์ž‘์€ ํ”Œ๋žซํผ์— ๋”ฐ๋ผ ํฌ๊ฒŒ ๋‹ค๋ฅด๋‹ค.

  1. ์• ์ดˆ์— strong order๋ฅผ ์ง€ํ–ฅํ•˜๋Š” ํ”Œ๋žซํผ(x86 ๋“ฑ)์—์„œ๋Š” Relaxed๋ฅผ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ Release-Acquire ๋ฐฉ์‹๊ณผ ๊ฑฐ์˜ ๊ฐ™๊ฒŒ ๋™์ž‘ํ•ด์„œ ์„ฑ๋Šฅ ์ด์ ์ด ๊ฑฐ์˜ ์—†๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ„์™€ ๊ฐ™์€ ๋ถ€์ž‘์šฉ๋„ ์—†์„ ๊ฒƒ์ด๋‹ค.
  2. ๋ฐ˜๋ฉด weak order๋ฅผ ์ง€ํ–ฅํ•˜๋Š” ํ”Œ๋žซํผ(arm ๋“ฑ)์—์„œ๋Š” Relaxed๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ฝ๊ฐ„์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์œ„์—์„œ ์„ค๋ช…ํ•œ ๋ถ€์ž‘์šฉ๋„ ํ•จ๊ป˜ ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.



Release-Acquire Ordering

์ด๊ฒŒ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ํ˜•ํƒœ์˜ Ordering์ด๋‹ค.
์ด 2๊ฐœ์˜ Ordering์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ตœ์ ํ™” ๋ฐฉ์ง€๋ฅผ ๋ณด์žฅํ•œ๋‹ค.


  1. Acquire๊ฐ€ ์žˆ๋‹ค๋ฉด, Acquire ์ดํ›„์— ๋ฐœ์ƒํ•œ ์—ฐ์‚ฐ์€ ํ•ญ์ƒ ๊ทธ ์ดํ›„์— ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ๋œ๋‹ค.

  2. Release๊ฐ€ ์žˆ๋‹ค๋ฉด, Release ์ด์ „์— ๋ฐœ์ƒํ•œ ์—ฐ์‚ฐ์€ ํ•ญ์ƒ ๊ทธ ์ด์ „์— ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ด ๋ณด์žฅ๋œ๋‹ค.



๊ทธ๋ž˜์„œ Relaxed์—์„œ ๋ฐœ์ƒํ–ˆ๋˜ ์ˆœ์„œ ๊ผฌ์ž„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์ด Release-Acquire๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ณดํ†ต atomic์œผ๋กœ read/write ์ž‘์—…์„ ํ•˜๋ฉด ์ฝ์–ด์˜ค๊ณ -์“ฐ๋Š” ์ˆœ์„œ๊ฐ€ ๋˜๋‹ˆ๊นŒ, load์— Acquire๋ฅผ ์ฃผ๊ณ  store์— Release๋ฅผ ์ฃผ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.




SeqCst Ordering

๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ํ˜•ํƒœ์˜ Ordering์ด๋‹ค.
์ด๊ฑธ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ์—ฐ์‚ฐ ์•ž๋’ค์— ๋‹ฌ๋ ค์žˆ๋Š” ์—ฐ์‚ฐ๋“ค์€ ์ˆœ์„œ๊ฐ€ ์ „๋ถ€ ๊ณ ์ •๋œ๋‹ค. ๋ชจ๋“  ์Šค๋ ˆ๋“œ์—์„œ ์ผ๊ด€๋œ ๋‹จ์ผ ์ˆœ์„œ๋ฅผ ๊ฐ•์š”ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ด๊ฑด ์–ด๋–ค ํ”Œ๋žซํผ์—์„œ ์‚ฌ์šฉํ•˜๋“  ๋น„ํšจ์œจ์ ์ธ ์ฝ”๋“œ ์ตœ์ ํ™”๋ฅผ ๋‚ณ๋Š”๋‹ค. memory fence ์ธ์ŠคํŠธ๋Ÿญ์…˜์ด ์‚ฌ๋ฐฉ์— ๋–ก์น ๋  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทธ๋ž˜์„œ ์‹ค์ œ ์‚ฌ์šฉ์€ ์ž์ œํ•˜๋Š” ํŽธ์ด ์ข‹๋‹ค. ๋Œ€์ฒด๋กœ๋Š” Release-Acquire๋งŒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•˜๋‹ค.
Release-Acquire๋กœ๋„ ์•ˆ๋œ๋‹ค๋ฉด ๋ญ”๊ฐ€ ์„ค๊ณ„๊ฐ€ ์ž˜๋ชป๋˜์—ˆ๋‹ค๊ณ  ๋ณด๋Š” ํŽธ์ด ํƒ€๋‹นํ•˜๋‹ค.




๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ๊ฐ„์˜ ์ˆœ์„œ ๊ผฌ์ž„ ๊ด€์ธก

์ด๊ฑด ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ atomic operation์„ ๊ต์ฐจํ•ด์„œ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—ฃ์ง€์ผ€์ด์Šค๋ฅผ ๋‹ค๋ฃฌ๋‹ค.

์•„๋ž˜๋Š” ๊ทธ๋ƒฅ 2๊ฐœ์˜ ์Šค๋ ˆ๋“œ์—์„œ ๊ฐ๊ฐ ๋ง์…ˆ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์ฝ”๋“œ๋‹ค. ๋ณ„๊ฑด ์—†๋‹ค.

๊ทธ๋ƒฅ ์ด๋Ÿฐ ๋А๋‚Œ์œผ๋กœ ๋‹จ์ผ atomic์„ ์“ธ๋•Œ๋Š” ์•„๋ฌด ๋ฌธ์ œ๊ฐ€ ์—†๊ณ , ์—ฌ๋Ÿฌ๊ฐœ์˜ atomic์„ ๋™์‹œ์— ์“ฐ๋”๋ผ๋„ ํฐ ๋ฌธ์ œ๋Š” ์—†๋‹ค.

ํ•˜์ง€๋งŒ ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋Ÿฐ์‹์œผ๋กœ atomic์„ ํ•ธ๋“ค๋งํ•˜๋ฉด

์šฐ๋ฆฌ๋Š” number์˜ store๊ฐ€ ๋จผ์ € ์‹คํ–‰๋œ ์ดํ›„์— number2์˜ store๊ฐ€ ์‹คํ–‰๋  ๊ฒƒ์ด๋ผ๊ณ  ๊ธฐ๋Œ€ํ•  ๊ฒƒ์ด๋‹ค.

๋ณดํ†ต์€ ๊ทธ๊ฒŒ ๋งž๋‹ค. ๋‹จ์ผ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ๊ทธ๋ ‡๊ฒŒ ๋™์ž‘ํ•˜๊ธฐ๋„ ํ•œ๋‹ค.
๋ฌธ์ œ๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ทธ๊ฒŒ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

๊ทธ๋ž˜์„œ ์˜๋„์ ์œผ๋กœ ์žฌํ˜„ํ•˜๊ธฐ๋Š” ๊ฝค ์–ด๋ ต์ง€๋งŒ, thread2์—์„œ๋Š” number๊ฐ€ 0์ด๋ฉด์„œ number2๊ฐ€ 20์ธ ๊ธฐ๋ฌ˜ํ•œ ์ƒํ™ฉ์„ ๊ด€์ธกํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

์•„๋ž˜๋Š” ์ˆœ์„œ ๊ผฌ์ž„ ํ˜„์ƒ์„ ์žฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์ œ ์ฝ”๋“œ๋‹ค. ์‹คํ–‰ํ•ด๋†“๊ณ  ์ข€ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ํ˜„์ƒ์„ ๊ด€์ธกํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

use std::sync::{atomic::AtomicI64, Arc};

fn main() {
    loop {
        let barrier = Arc::new(std::sync::Barrier::new(2));

        let number = Arc::new(AtomicI64::new(0));
        let number2 = Arc::new(AtomicI64::new(0));

        let thread1 = {
            let number = number.clone();
            let number2 = number2.clone();
            let barrier = barrier.clone();
            std::thread::spawn(move || {
                barrier.wait();
                number.store(10, std::sync::atomic::Ordering::Relaxed);
                number2.store(20, std::sync::atomic::Ordering::Relaxed);
            })
        };

        let thread2 = {
            let number = number.clone();
            let number2 = number2.clone();
            let barrier = barrier.clone();
            std::thread::spawn(move || {
                barrier.wait();
                let number = number.load(std::sync::atomic::Ordering::Relaxed);
                let number2 = number2.load(std::sync::atomic::Ordering::Relaxed);

                if number == 0 && number2 == 20 {
                    println!("number = {}", number);
                    println!("number2 = {}", number2);
                }
            })
        };

        thread1.join().unwrap();
        thread2.join().unwrap();
    }
}

ํ”Œ๋žซํผ์ด๋‚˜ ํ”„๋กœ์„ธ์„œ, ์ตœ์ ํ™” ์ˆ˜์ค€์— ๋”ฐ๋ผ์„œ ์žฌํ˜„๋ฅ ์€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

์ด๊ฑด ์„œ๋กœ ๋‹ค๋ฅธ CPU ์บ์‹œ์™€ ๋‚ด๋ถ€ ๋ฒ„ํผ๊ฐ€ ๋™์ผํ•œ ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•ด ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ’์„ ๋ณด์œ ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•œ๋‹ค.
์ฆ‰, ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์˜ค๋ž˜๋œ ๊ฐ’์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ number์™€ number2๋Š” ์ €์žฅ๋˜๊ธด ํ–ˆ์ง€๋งŒ ์•„์ง ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์ „ํŒŒ๋˜์ง€๋Š” ์•Š์€ ๊ฒƒ์ด๋‹ค. ์บ์‹œ ์ „ํŒŒ ์ˆœ์„œ๋Š” ์ €์žฅ ์ˆœ์„œ์™€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” ๋น„๋‹จ memory ordering์— ํ•œ์ •๋œ ๋ฌธ์ œ๋Š” ์•„๋‹ˆ๋‹ค. ordering์„ ๋ฐ”๊พธ๋”๋ผ๋„ ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ์„ ํ•  ์ˆ˜๋Š” ์—†๊ณ , ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์ด ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ฐฐ๋ฆฌ์–ด๋‚˜ mutex, lock ๊ฐ™์€ ์ˆ˜๋‹จ์œผ๋กœ ๋น„๊ด€์ ์ธ ๋ฝ์„ ์žก์•„์•ผ ํ•œ๋‹ค.



์ฐธ์กฐ
https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EB%A6%AC_%EB%B0%B0%EB%A6%AC%EC%96%B4
https://velog.io/@codingskynet/C11-Memory-Model-Atomic%EB%B6%80%ED%84%B0-Lock-Free-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EA%B9%8C%EC%A7%80
https://stackoverflow.com/questions/55680665/how-to-understand-relaxed-ordering-in-stdmemory-order-c
https://doc.rust-lang.org/nomicon/atomics.html
https://preshing.com/20120930/weak-vs-strong-memory-models/