D 언어에서 권하는 다중 쓰레드 운영 방식은 immutable
로 선언하여 데이터가 변하지 않도록 하고, 메시지 패싱(message passing)을 사용해 실행 순서를 제어하는 것입니다. 다만, 기존의 락(lock)을 이용한 동기화(synchronization) 또한 D 언어에서 지원하고 있습니다. 여러 쓰레드에서 동시에 이용할 값이나 객체는 shared
라는 키워드로 표시해둘 수 있습니다.
shared
키워드는 여러 쓰레드에서 공유될 수 있도록 합니다.
shared(int)* p = new int;
int* t = p; // 오류: shared는 shared 끼리만 처리되어야합니다.
std.concurrency
패키지의 send
함수는 immutable
또는 shared
로 표기된 값이나 객체를 복사하여 메시지로 전달합니다. shared
는 이행적(transitive) 성격을 가지고 있어, class
나 struct
가 shared
로 선언되면 그 밑의 내부 함수와 내부 변수 모두가 shared
상태가 됩니다.
다만 예외적으로 이전 섹션에서 배운 static
의 경우, 쓰레드 지역 변수(thread local storage, TLS) 로 별도로 관리되기 때문에 해당하지 않습니다.
synchronized
로 동기화 블럭을 만들면 별도로 뮤텍스(mutex), 세마포어(semaphore) 등의 락(lock) 구현 없이, 오직 한 쓰레드만 실행되어야하는 임계 영역(critical section)을 손쉽게 지정할 수 있습니다. 이 메커니즘은 컴파일러에 의해 추가됩니다.
synchronized {
importStuff();
}
class
내부 함수에서는 어느 스코프(scope)의 값까지 synchronized
대상에 넣을지에 대한 논란이 있습니다. 이를 최소화하기 위해 내부 값/객체를 지정한 형태인 synchronized(member1, member2)
코드 형태로만 동기화 블럭을 만들 수 있습니다.
효율적이진 않지만, 필요하다면 클래스 전체를 synchronized
동기화 블럭으로도 만들 수 있습니다. 컴파일러는 이 클래스에 접근하려는 모든 경우에 대해 한번에 하나의 쓰레드만 접근하도록 통제된 코드를 만들 것입니다.
아토믹 연산(atomic operation)을 shared
로 선언된 변수에 적용하려면 core.atomic.atomicOp
이라는 보조 함수를 사용합니다. 아토믹 연산은, 원자(atom)가 더이상 쪼개지지 않는다는 점에서 나온 단어로, 다음 쓰레드가 접근하기 전에 현재 쓰레드에서 할 연산을 모두 수행함으로써 다중 쓰레드 환경에서 발생할 수 있는 값/상태 이상을 예방하는 기법입니다.
shared int test = 5;
test.atomicOp!"+="(4);