Tips2017. 10. 20. 01:32

재밌는 현상을 발견해서 포스팅을 남긴다.


Python으로 class를 지정해서 코딩할 때, 한 클래스 내에서 리스트를 사용할 일이 있어서 다음과 같은 형태로 클래스를 정의했다.


class foo:
    name    = None
    foo_list = []


해당 클래스의 객체를 여러개 만든 뒤, 들어오는 input에 대해 name을 확인하여 각기 다른 foo 객체의 foo_list에 삽입하도록 했다. 

이후 여러 foo 객체를 오가며 foo_list에 삽입된 항목들을 출력하도록 했더니... 오잉? 모든 항목이 동일한 리스트에 들어가 있는 것이 아닌가?


열심히 디버깅 하다가 미심쩍은 부분이 있어서 다음과 같이 변경하였다.


class foo:
    name    = None
    foo_list = None
    def __init__ (self):
        foo_list = []


그러고 나니 각 객체 별로 별도의 리스트를 잘 출력하는 것이었다.

그러니까, class의 멤버 변수를 정의할 때, 초기값을 바로 때려넣어버리면 그게 일종의 static type이 되어서 모든 객체에서 공유하는 멤버 변수가 되는 것이었다. 수정한 코드와 같이 init을 통해 객체가 생성될 때 리스트를 선언하여 사용하면 각 객체 별로 별도의 리스트를 가질 수 있게 되는 것이다.

뭐, 저 용어들이 엄밀하게 따져서 맞는 용어인지는 모르겠다. 어쨌든 내 전문 분야는 C 언어이고, C 언어의 지식으로 해석해봤을 때 저게 static type (혹은 전역변수)으로 보일 뿐이다.



Posted by 곰푼
Writings/Operating System2017. 10. 18. 15:31

클락업을 통한 싱글 코어의 발전이 power wall에 가로막힌 이후, CPU의 발전 방향은 코어의 갯수를 늘리는 쪽으로 선회하였다. 그에 따라 멀티코어, 매니코어에 이르는 다양한 변종들이 등장하게 되었으며, 이로 인해 애플리케이션 및 운영체제의 확장성(scalability)이 중요한 문제로 대두되게 되었다. 


확장성이란 사전적인 의미로 보았을 때 늘어난 수요에 맞춰 얼마나 유연하게 대응할 수 있는지를 나타내는 척도라고 할 수 있다. 애플리케이션을 뒷 받침 하는 시스템의 입장에서 확장성이란 단어를 협의적으로 해석하면 늘어난 자원에 맞추어(e.g., 코어 수) 성능이 얼마나 향상되는 지를 나타내는 척도라고 할 수 있다. 자원이 늘어남에 따라서 성능이 비례하여 향상되면 확장성이 좋다 할 수 있고, 성능이 그대로이거나 혹은 더 떨어지게 된다면 확장성이 나쁘다라고 할 수 있다.


이 포스팅에서는 운영체제를 주로 다룰 것이므로 운영체제와 관련된 문제만을 살펴보도록 할 것이다. 확장성을 저해하는 요소는 운영체제 내에 다양하게 산재해 있지만, 그 중에서도 주된 요인을 꼽아보자면 단연 동기화(synchronization) 메커니즘이라고 할 수 있다.


비단 멀티코어 환경이 아니더라도 CPU의 시분할을 통한 멀티 프로그램 기법으로 인해 하나의 공유 자원에 대해 여러 프로세스가 동시에 접근할 수 있게 되었다. 각 프로세스는 특정 코드를 실행시키는 동안 자신이 접근하는 자원이 최소한 그 코드 내에서는 독점적으로 사용할 것을 요구하며, 이 요구사항이 지켜지지 않을 경우 일관성(consistency) 문제가 발생하게 된다. 


다음의 예시를 보자.


int a = 0, b = 0;

void func (void) {
    b = a + 1;  
    a = b; 
}

void proc_a (void) {
    func();
}

void proc_b (void) {
    func();
}


8번째 줄의 proc_a와 12번째 줄의 proc_b가 각각 별개의 프로세스에서 실행되는 코드라고 가정하자. proc_aproc_b가 동시에 실행된 뒤 a와 b를 출력하면 어떤 결과가 나올까? 총 두 가지의 결과를 예측해 볼 수 있다. 첫째로는 (a = 2, b = 2), 둘째로는 (a = 1, b = 1).  func()이 진행 중일 때 타이머 인터럽트가 발생하여 5번째 줄을 실행하기 전에 컨텍스트 스위치가 발생할 경우 두 번째의 결과가 발생하게 된다. 이러한 결과를 얻어내기 까지 발생할 수 있는 절차의 가지 수는 더욱 많다. 


  • proc_a -> proc_b
  • proc_b -> proc_a
  • proc_a -> (scheduling) proc_b -> proc_a
  • proc_b -> (scheduling) proc_a -> proc_b


위와 같은 상황이 발생할 경우, 사용자 혹은 애플리케이션의 입장에서는 같은 코드를 실행시켰음에도 불구하고 나오는 결과가 매번 달라질 수 있게된다. 따라서, 운영체제에서는 위와 같은 상황을 방지하기 위해 동기화 메커니즘을 제공한다. 대부분의 경우 동기화 메커니즘은 특정 영역(이를 critical section이라 부른다)에 대한 접근을 직렬화(serialize)하는 것으로 이러한 문제를 해결한다. 


void proc_a (void) {
    synch_region {
        func();
    }
}

void proc_b (void) {
    sync_region {
        func();
    }
}

<caller-side synchronization>

직렬화란, 동시에 오직 한 프로세스만 특정 영역에 접근시키도록 하는 것을 의미한다. 동시에 여러 프로세스가 접근할 경우, 뒤늦게 접근하는 프로세스는 앞서 진입한 프로세스가 작업을 마칠 때 까지 기다려야만 한다. 코드에서 synch_region으로 표시된 영역이 바로 이러한 영역이 되겠다.

위와 같이 호출하는 코드에서 동기화 영역을 표시하는 경우도 있으며, 반대로 호출되는 코드에서 동기화를 시키는 경우도 있을 것이다. 

void func (void) {
    synch_region {
        b = a + 1;  
        a = b; 
    }
}

<callee-side synchronization>

코드에 표시된 synch_region은 동기화 메커니즘의 일종의 예시인 것을 기억하자. 여러 논문 및 구현들을 통하여 다양한 방식의 동기화 메커니즘이 제안되어 왔으며, 위와 비슷한 형태를 취할 수도, 혹은 다른 형태를 취하게 될 수도 있다.


운영체제는 일반적으로 여러 형태의 locking primitive들을 통하여 동기화 기능을 제공한다. 대표적으로 spinlock과 같은 busy-loop 기반의 locking primitive가 있으며, 이는 효과적인 동기화 방법을 제공하지만 확장성을 저해시킬 수도 있다. 예를 들어 여러 코어에서 동작하는 프로세스들이 임계 영역(critical section - 동기화 메커니즘에 의해 보호받는 영역)을 만날 경우, 앞서 진입한 프로세스가 필요한 작업을 다 수행할 때 까지 기다려야만 한다. 이 임계 영역이 길어질 경우, 그만큼 대기 시간이 길어지게 되므로 자연스럽게 대기중인 프로세스가 점유하고 있는 코어의 시간을 낭비하게 된다. 


따라서 spinlock과 같은 busy-loop 기반의 동기화 방식들은 임계 영역의 길이를 최대한 줄일 것을 전제로 하고 있으며, 여의치 않을 경우 mutexsemaphore등의 block-based locking primitive들을 쓸 것을 추천한다. 이러한 lock들은 기다리는 프로세스를 sleep 상태로 전환함으로써, 해당 프로세스가 점유하고 있는 컴퓨팅 자원을 다른 프로세스에게 양도할 수 있도록 한다. 이를 통해 시스템은 낭비되는 컴퓨팅 자원을 효율적으로 활용할 수 있게 된다.


위와 같은 방식 외에도, 보다 확장성을 고려한 형태의 locking primitive들도 많이 고안되었다. reader-writer lock, ticket lock, queue spinlock, mcs lock, seqlock 등이 바로 확장성을 고려한 locking primitive 들이다.


앞으로 이와 같은 locking primitive들에 대해 한번 알아보려고 한다.

Posted by 곰푼
Reviews/Book logs2017. 9. 11. 03:37


시대정신이란 말이 있는데 대충 시민들이 공유하는 그 시대를 대표하는 의식 정도가 될 것이다. 가령 우리나라를 예로 들자면 적폐청산이 있겠다.


그러면 국경을 넘어선 시대정신은 무엇이 있을까? 나는 감히 불평등의 해소가 가능성이 높을 것이라 본다.
사실 우리는 본능적으로 불평등이 어떠한 형태로 나타나고, 또 어떻게 생성되는지 파악하고 있다. 학자들은 그러한 얼개를 구체화하기 위해 통계자료를 구하고 분해한 뒤 분석한다.
그런 관점에서 이 책은 간결하며 명료하다.


근로소득과 자본소득을 구별한 뒤, 현재는 자본소득이 높은이가 근로소득의 수준 또한 높음을 통계자료를 근거로 보여준다. 이른바 금수저이다.


수많은 경제학 이론이 미래를 예측했으나 대부분 빗나갔으며, 자신 또한 그럴 것이라고 얘기하며 그럼에도 불구하고 미래를 조심스럽게 예측한다. 저자는 경제학자들이 불평등이 비치는 렌즈로 세상을 바라보기 시작했다며 적어도 그 부분은 다를 것이라 얘기한다.


재밌는건 책의 결론인데, 그 부분의 사진을 첨부한다.





'Reviews > Book logs' 카테고리의 다른 글

헤아려본 슬픔 - C.S. 루이스  (0) 2012.02.03
Posted by 곰푼