동시성이란? 가시성이란? 원자성이란?
멀티 쓰레드 프로그래밍에 대해 보다보면 지겹게 나오는 단어가 저 3가지다. 처음 쓰레드를 공부할 때는 동시성이고 나발이고 그냥 냅다 코드부터 갈기고 스택오버플로우에 머무는 훌륭한 코드 몽키였지만 이제는 코루틴을 공부하다 보니 volatile 어노테이션과 가시성 키워드가 나와서 모르는 건 못 참지 마인드로 포스팅한다.
먼저 동시성, 가시성, 원자성에서 동시, 가시, 원자의 각 사전적 정의는 아래와 같다.
동시 : 같은 때나 시기, 어떤 사실을 겸함 / 똑같은 것으로 봄
가시 : 눈으로 볼 수 있는 것
원자 : 물질의 기본적 구성 단위
이제 각 단어의 사전적 정의를 검색해봤다. 네이버 사전 기준 가시성은 검색되지 않아서 지식백과의 내용을 가져왔고 원자성은 위키백과로 리다이렉트되서 해당 위키 페이지의 내용을 가져왔다.
동시성 : 어떤 두 사건이 같은 시간에 일어나는 것
가시성 : 자료의 구조가 갖고 있는 복잡한 부분이 프로그래머나 사용자 눈에는 보이지 않게 돼 있는 상태
원자성 : 어떤 것이 더 이상 쪼개질 수 없는 성질. 어떤 것이 원자성을 갖고 있다면 원자적이라고 한다. 어떤 작업이 실행될 때 언제나 완전하게 진행돼 종료되거나 그럴 수 없는 경우 실행을 하지 않는 경우를 말한다. 원자성을 갖는 작업은 실행되어 진행되다가 종료하지 않고 중간에서 멈추는 경우는 있을 수 없다
동시성은 대충 생각나는 그 뜻하고 뭐 다를 게 없고, 가시성의 뜻을 보면 객체지향의 특징 중 하나인 캡슐화와 은닉성과 비슷해 보인다. 그러나 원자성은 더 못 쪼갤 때까지 쪼개서 더는 못 쪼개는 성질이라는 것 정도로 이해했다. 그런데 이게 어쨌다는 건가? 다른 곳에서 설명하는 동시성, 가시성, 원자성의 뜻을 확인해봤다.
동시성이란 한 CPU에서 동시에 여러 작업을 하는 것처럼 보이게 만드는 것이다. 한 CPU에서 2개의 프로세스가 있다고 가정한다. 이 둘은 엄청나게 짧은 시간에 컨텍스트 스위치가 일어나며 번갈아 실행된다. 그래서 사람이 볼 때 동시에 동작하는 것처럼 보인다. 이것이 프로그래밍 세계에서의 동시성이다
https://roeldowney.tistory.com/438
동시성은 한 번에 많은 일을 다루는 걸 의미한다. 여러 작업들을 작게 쪼개서 번갈아 가며 수행하는 걸 의미한다. 컴퓨터는 굉장히 빠른 속도로 처리하기 때문에 (사람은)동시에 처리되는 것처럼 느껴지지만 시간 관점으로는 동시가 아니다. 이 관점으로 보면 싱글 코어 컴퓨터가 어떻게 멀티 태스킹이 가능한지 알 수 있다. 현실 세계에서 병렬적으로 일어나는 일들을 컴퓨터 세계에서 구현하기 위한 방법 중 하나가 동시성이다
http://jeremymanson.blogspot.com/2007/08/atomicity-visibility-and-ordering.html
(중략)...원자성은 어떤 행동과 일련의 행동이 나눌 수 없는 영향을 미치는지를 다룬다. 이것은 프로그래머에게 가장 친숙한 동시성의 측면이다. 일반적으로 상호 배제의 관점에서 생각된다. 가시성은 한 쓰레드의 효과를 다른 쓰레드에서 볼 수 있는 시기를 결정한다. 순서 지정은 한 쓰레드의 작업이 다른 쓰레드에 대해 순서 없이 발생하는 것으로 볼 수 있는 경우를 결정한다...(중략)...원자성은 동시 프로그래밍의 전통적인 버그베어다. 이를 시행한다는 건 일반적으로 잠금(locking)을 사용해서 상호 배제를 시행하는 걸 의미한다...(중략)
https://steady-coding.tistory.com/554
(중략)...가시성이란 공유 데이터를 읽는 경우의 동시성만 보장하는 것이라 생각하면 된다
https://velog.io/@meme2367/%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-volatile
가시성이란 값을 사용한 다음 블록을 빠져나가고 나면 다른 쓰레드가 변경된 값을 즉시 사용할 수 있게 해야 한다는 뜻이다. 적절하게 동기화시키지 않으면 다른 쓰레드에서 최신 값이 아닌 예전 값을 읽게 된다.
가시성, 즉 잘 보임의 대상은 무엇인가? 위에서 이미 거론했지만 우리는 공유하는 변수에 대해 다루고 있다. int i = 10; 이라고 썼을 때 그냥 메모리에 들어가면 좋겠지만 쓰레드는 동작하는 시점에 CPU의 코어를 점유하고 동작한다. 선언한 변수의 값이 메모리에만 존재하는 게 아니라 CPU 캐시 영역에도 존재한다. 이는 CPU가 메모리에서 값을 읽어오고 다시 쓰는 시간을 아끼기위함이다. 더 큰 문제는 CPU 캐시의 값이 언제 메모리로 옮겨갈지도 모른다는 것이다. 이를 해결하는 개념이 가시성이다
동시성
- 하나의 코어에서 여러 쓰레드가 번갈아가며 실행하는 성질을 의미
- 실제로는 한 코어에서 한 쓰레드만 실행하고 있고 번갈아가면서 실행하고 있기에 동시에 실행되는 것처럼 보이는 것
- 쓰레드 개수가 코어 수보다 많으면 쓰레드 스케줄링을 통해 쓰레드를 어떤 순서로 동시성으로 실행할지 결정하는 게 필요
- 자바는 우선순위 방식, 순환할당 방식으로 쓰레드 스케줄링을 구현
https://www.vogella.com/tutorials/JavaConcurrency/article.html#what-is-concurrency
동시성은 여러 프로그램 또는 프로그램의 여러 부분을 병렬로 실행할 수 있는 기능이다. 시간이 많이 걸리는 작업을 비동기식으로 or 병렬로 수행할 수 있으면 처리량, 프로그램의 상호 작용성이 향상된다. 최신 컴퓨터에는 한 CPU 안에 여러 CPU 또는 코어가 있다
https://bluekms21.gitbooks.io/femp/content/05_WhatDoWeNeed.html
원자성이란 더 이상 쪼개지지 않는 최소 단위를 의미한다. 원자적 메모리란 어떤 쓰레드가 메모리를 참조해서 처리하는 일련의 과정이 더 이상 쪼개질 수 없는 최소 단위로 일어나는 메모리를 뜻한다...(중략)...실제 프로그래밍에선 변수 하나하나의 원자성보다 더 큰 단위의 원자성이 필요하다
https://mygumi.tistory.com/111
원자성은 깨지지 않는 성격이기에 중단되지 않는 연산이라고 볼 수 있다. int count = 0; 은 원자 연산이고 count++는 비원자 연산이다. count++는 3가지 작업으로 분리된다.
1. count 변수값을 가져온다
2. count 변수값을 증가시킨다
3. 변경된 count 변수를 저장한다
비원자 연산은 작업이 분리되서 이뤄져 한 번에 처리되지 않는다...(중략)
정리하면 이렇게 될 것 같다.
- 동시성 : 한 코어 안에서 쓰레드가 여러 작업을 엄청 빠르게 번갈아 실행하는 성질. 이 속도가 빨라서 사람은 동시에 실행되는 것처럼 보인다
- 가시성 : 쓰레드가 항상 최신 값을 받아볼 수 있게 하는 성질
- 원자성 : 어떤 작업이 프로그램(소스코드) 안에서 가장 작은 단위라서 더 이상 다른 작업으로 나눌 수 없는 성질