오늘은 기초 전산학/컴공 상식을 좀 복습해 보고자 한다.

※ 지금과 같은 컴퓨터의 근간이 갖춰진 과정

1. 순 전자식

이로써 인간이 발명한 계산 기계는 엔진 달린 주판 수준을 넘어서 자신의 모든 내부 상태를 전자 신호만으로 광속으로 표현할 수 있게 됐다. 에니악이 순 전자식 컴퓨터로서는 거의 최초 원조라 여겨진다. 이거 이후로 컴퓨터는 진공관, 트랜지스터, IC, (V)LSI 회로 순으로 그야말로 엄청난 공간 워프를 거듭하면서 작아지고 빨라지기 시작했다.

전자식이 아니라면? 컴퓨터도 엔진이나 모터가 달린 채로 만들어졌을 것이다. 19세기에 영국의 수학자 찰스 배비지는 '프로그래밍 가능한 보편적인 계산 기계'인 '해석 기관'이라는 걸 제안하고 만들려 했다. 시대를 아득히 앞서 간 물건이었는데, 그걸 가동하기 위해서 무려 증기 기관을 접목할 생각까지 했었다. 지금 같은 눈부신 전자 공학 기술이 없던 시절이니 당연히 기계식밖에 선택의 여지가 없었던 것이다.

그리고 1940년대 초에 에니악 이전에 등장했던 '하버드 마크 1'이라는 기계는 '전자식 계산기'라기보다는 '전동식 계산기'에 더 가까웠다. 복잡한 배선과 릴레이뿐만 아니라 4마력짜리 모터가 달려 있었다. 이건 냉각팬 모터가 아니며 하드디스크 같은 기계식 보조 기억장치용 모터도 아니고, CPU의 실제 계산 동작을 위한 모터였다..;;

2. 2진법 기반

사람이나 열 손가락이 달려 있으니 10진법이 편하지, 기계는 단순한 2진법이 더 편하다. 컴퓨터가 전자식으로 바뀐 뒤부터는 그 차이가 더욱 두드러졌다.
하지만 극초창기에는 숫자 진법을 변환하는 것조차 쉬운 작업이 아니었고, 정수가 아닌 부동소수점으로 가면 숫자를 표현하는 난이도가 더 올라갔다. 더구나 컴퓨터는 처음부터 포탄 탄도 예측, 풍동 실험, 일기예보 시뮬, 모의 핵실험처럼 천상 실수 연산이 잔뜩 필요한 과학 영역에서 쓰였다.

그러니 에니악 같은 컴퓨터는 10진법 기반으로 만들어졌다. 4비트를 한 자리로 묶어서 0~9를 표현하는 BCD 코드 기반이었지 싶다. 하지만 10진법 숫자를 처리하기 위해서 어차피 2진법 기반의 각종 논리 연산 회로를 구현해야 했을 것이고, 후대의 컴퓨터들은 얼마 가지 않아 native 2진법 기반으로 다 바뀌었다.

3. 튜링 완전

프로그램이 하드코딩된 고정된 변수가 아니라 메모리에 기록된 값을 토대로 또 임의의 위치의 메모리를 읽고 쓸 수 있고(= 배열, 포인터 등을 이용한 복합 자료형. 공간 확장),
런타임 때 결정되는 값의 조건에 따라 반복과 분기가 가능하다면 (= 시간 확장)
그런 계산 모델은 Turing-complete하다고 여겨진다. 즉, 단순 계산기를 넘어 뭔가 본격적으로 프로그래밍이 가능해진다는 것이다.
그 열악한 에니악조차도 설계 구조는 튜링 완전한 형태였다고 한다.

4. 프로그램 내장형

컴퓨터에게 시킬 작업을 변경하기 위해 매번 회로 배선을 뜯어고치고 바꾸는 게 아니라, 한 메모리에서 코드와 데이터를 일체로 내장시킨다. 이 개념까지 정립됨으로써 비로소 컴퓨터는 정말 유연하고 무한한 확장성을 지닌 물건으로 변모했으며, 컴퓨터에서 하드웨어와 별개로 '소프트웨어'라는 것이 존재할 수 있게 됐다.
또한, 메모리가 컴퓨터의 성능에서 차지하는 비중이 아주 커졌다. 프로그램을 메모리에다 처음으로 입력시킬 때는 과거엔 천공 카드 같은 불편한 매체가 쓰였지만, 나중에는 더 간편한 키보드로 대체됐다.

저 아이템들 하나하나가 그야말로 병아리가 알을 깨고 세상으로 나오는 급의 대격변이고 혁신이었다.
인류 역사상 이런 네 조건을 모두 만족하는 컴퓨터가 발명되고 등장한 지 아직 100년이 채 지나지 않았다. 자동차와 비행기의 역사는 100년을 넘었지만 컴퓨터는 아직 그렇지 않고 오히려 2차 세계 대전 이후 냉전 때부터 발전해 왔다.
그 짧은 기간 동안 컴퓨터가 인류 역사상 유례가 없이 세상을 바꿔 놓은 걸 보면.. 정말 전율이 느껴지지 않을 수 없다.

※ 메모리 계층

컴퓨터는 모름지기 정보를 다루는 기계이다. 그리고 앞서 언급했던 프로그램 내장 방식의 특성상, (1) 실행할 코드와 (2) 그 코드가 처리할 데이터가 모두 메모리에 담겨 있어야 한다. 쉽게 말해 정보를 담을 그릇이 필요하다.
그런데 컴퓨터가 취급하는 메모리라는 게 여러 종류가 있고, 이들은 속도와 용량, 단위 용량당 가격이 극단적으로 반비례하는 관계이다. 그렇기 때문에 종류별로 일종의 '메모리 계층'이 존재한다.

1. 레지스터(수십~수백 byte)

CPU 구성요소의 일부이다. 당연히 CPU 차원에서 최고속으로 직통으로 값을 읽고 쓸 수 있다.
현재 프로그램이 실행되고 있는 지점(메모리 위치), 수만 번씩 실행되는 for 문 loop 변수, C++ 함수의 경우 this 포인터, 산술 연산 명령에 쓰이는 피연산자와 연산 결과 같은 정~말 원초적인 값들이 이곳에 저장된다.
실행되는 스레드의 context가 바뀌면 레지스터의 값도 자기 상태의 것으로 바뀐다.

2. 캐시 메모리(수백 KB~수 MB)

CPU 자체는 아니지만 여전히 CPU의 연장선 격이며 접근 속도가 매우 빠르다. CPU가 사람 두뇌이고 레지스터가 손의 손가락이라면 캐시는 의수 정도는 된다.
얘는 CPU 속도와 메모리 속도의 격차가 커지면서 메모리로 인한 병목을 줄이기 위한 버퍼 차원에서 도입되었다.

캐시도 레벨 1, 레벨 2로 나뉘긴 하는데, 인텔 x86 CPU에서 제일 원초적인 L1 캐시는 80486 때 8K짜리가 도입된 것이 최초이다. 반대로 펜티엄 2이 나왔던 시절에 셀러론 프로세서는 L2 캐시를 제거하거나 용량을 팍 줄인 저가형 모델이었다.

3. 일반 메모리(수십 GB)

CPU의 외부에 있기 때문에 위의 것들보다는 느리지만, 그래도 보조 기억장치보다는 여전히 훨씬 빠르다. 이들 메모리는 전원이 끊어지면 내용이 다 지워지는 휘발성 메모리이다. 이제 신체 접근성으로 치면 의수를 넘어서 핸들과 버튼으로 따로 조작하는 로봇 팔과 비슷하다고 볼 수 있겠다.

4. 하드디스크(수 TB)

디스크부터는 보조 기억장치이기 때문에 이건 CPU의 명령만으로는 직접 접근조차 할 수 없다. 운영체제라는 소프트웨어가 구현해 놓은 파일 시스템에다 해당 운영체제 API를 통해 요청해야만 데이터를 읽고 쓸 수 있다. 파일 시스템은 열고 닫는 상태를 따로 보관하고 관리해야 하며, 프로그램의 입장에서는 여는 작업이 실패하는 상황에 대한 대비가 필요하다.
사람으로 비유하면 내 손으로 뭔가를 직접 조작하는 게 아니라, 남에게 말로 부탁을 해서 간접적으로 뭔가를 요청하고 움직이는 형태가 된다.

그 대신 보조 기억장치는 전원이 끊어진 뒤에도 기록을 남기고 보존할 수 있다. persistency를 보장하려다 보니, 하드디스크는 컴퓨터에서 전자식이 아닌 기계식으로 동작하는 얼마 안 되는 부품 중 하나가 돼 있다. 플래시 메모리는 '일반 메모리'의 성격에 더 근접해 있는 기억장치이지만, 가격과 용량 문제 때문에 하드디스크를 완전히 대체하는 구도는 못 된다.

캐시 메모리에서 캐시 미스가 나서 더 느린 일반 메모리까지 내려가서 데이터를 가져오는 게, 아래의 운영체제의 가상 메모리 체계에서 페이지 폴트가 발생해서 디스크의 페이지 파일에서 데이터를 가져오는 것과 비슷한 구도이다. 메모리 공간 자체가 CPU의 일부는 아니지만, 보호 모드 가상 메모리 구현을 위한 주소 변환은 CPU 차원의 지원을 따로 받아서 이뤄진다.

메모리가 비싸고 귀하고 부족하던 옛날에는 가상 메모리라는 게 디스크를 메모리 보충분처럼 사용하는 메커니즘이기도 했다. 비록 속도는 안드로메다로 가 버리지만, 그래도 아예 안 돌아가는 것보다는 나으니 better late than never이다. 요즘 운영체제들은 memory mapped file이라고 디스크를 반쯤 메모리 다루듯이 포인터로 접근시켜 주는 API를 제공하는데, 가상 메모리를 구현하면서 내부적으로 구현된 기능을 사용자도 적절하게 활용하라고 떼어 준 것에 가깝다.

또한, 가상 메모리와는 별개 개념으로.. 레지스터와 메모리 사이에 '캐시 메모리'가 있듯이, 메모리와 디스크 사이에 '디스크 캐시'라는 계층이 존재한다. 이게 잡아먹는 메모리 양이 만만찮지만 도스 시절에 smartdrv 유틸로 수백 KB~2MB 남짓만 캐시를 잡았어도 체감 성능 향상 효과가 장난이 아니었다. 이거 없이 곧이곧대로 찔끔찔끔 디스크에 접근해서는 오늘날의 방대한 컴퓨터 시스템이 돌아가질 못한다. 그만치 메모리와 디스크 사이의 속도 격차 병목이 엄청나다는 뜻이다.

5. 자기 테이프(수백 TB~수 PB)

아주 극단적인 보조 기억장치이다. 느리고 랜덤(임의 위치) 접근이 안 된다는 엄청난 단점이 있지만, 용량이 가히 압도적이고 가격이 저렴하다. 그렇기 때문에 서버 전체 내지 매일 생성되는 방송국 동영상 같은 엄청난 양의 데이터를 오로지 백업· 보존만 할 목적으로 일부 연구소나 기업에서 테이프가 여전히 사용되고 있다. 마치 국제 화물 운송에서 선박이 차지하는 위상(느리지만 엄청난 수송량)과 비슷하고, 프린터계에서 도트 프린터의 먹끈 카트리지(원시적이지만 타의 추종을 불허하는 저렴함)와 비슷하다.

메모리야 컴퓨터 프로그램들이 맨날 하는 짓이 저걸 건드리는 것이고, 보조 기억장치는 파일을 읽고 쓰는 운영체제 API를 통해 사용 가능하다.
레지스터의 경우, C/C++ 언어에는 특정 정수 변수를 가능한 한 저기에 얹어 달라고 컴파일러에게 요청하는 register이라는 키워드가 있다. 함수에 inline이 있다면 변수는 저게 있는 셈이다. for문 loop 변수가 레지스터에 올라가면 좋다.
물론, inline 함수는 재귀호출을 해서는 안 되며, 레지스터 등재 변수는 주소 참조(단항 & 연산자)를 해서는 안 된다.

이렇게 타 메모리나 디스크나 레지스터와는 달리, 캐시 메모리만은 적중률을 올리기 위해 소프트웨어가 직접 접근하고 개입하는 방법이 딱히 존재하지 않는다. 멀티코어 병렬화를 위해서는 CPU 직통 명령인 인트린식 같은 것도 있는데 캐시는 활용 방식이 소프트웨어가 아닌 오로지 CPU의 재량인가 보다.
이렇게 존재감이 없음에도 불구하고 캐시 메모리의 양과 성능은 클럭 속도 다음으로 컴의 속도에 직접적인 영향을 끼치는 요인이다.

※ 인텔 x86

인텔 x86은 전세계의 PC 시장을 완전히 석권한 기계어 아키텍처이다. 애플 맥 진영이 x86으로 갈아탄 지 이미 10년이 넘었고, 슈퍼컴퓨터조차도 Cray 같은 슈퍼컴 전용 아키텍처가 진작에 다 망하고 x86이 코어 수를 늘려서 야금야금 파고들고 있다.

하지만 x86은 CPU를 만들던 기술과 방법론이 지금과 같지 않던 초창기, 특히 메모리 가격이 왕창 비싸던 시절을 기준으로 기반이 설계되었으며 16, 32, 64비트로 올라가는 과정에서도 하위 호환성을 잘 유지하고 있다. 그래서 넘사벽급의 범용성과 시장 경쟁력은 확보했지만, 내부 구조가 갈수록 왕창 지저분해지고 스마트폰용 ARM 같은 후대의 최신 CPU들의 유행과는 영 동떨어진 형태가 됐다.

  • 범용 레지스터 수가 유난히 매우 적음. R## 이렇게 수십 개씩 번호가 붙는 게 아니라 EAX EDX ESI EBP 등 꼴랑 8개로 끝인 건 x86이 예외적이고 특이하기 때문이다. 함수에다가 매개변수를 올리는 주 방식도 x86은 당연히 레지스터가 아닌 스택 기반이다. 이 때문에 컴파일러 백 엔드를 개발하는 방법론이 x86 타겟 계열과 타 아키텍처 계열은 서로 완전히 다르며, x86은 오늘날 컴공과에서 컴파일러 제작 교육용 교보재로 쓰이기에는 영 좋지 못한 타겟 아키텍처이다.
  • 메모리를 조밀하고 compact하게 쓰는 대신에, 디코딩이 복잡하고 더 어려운 CISC 가변 길이 방식으로 명령어를 기술한다. 한 인스트럭션으로 연산에다 메모리 조작까지 몽땅.. 이런 식으로 많은 지시를 함축하고 있는 편이다. 자동차 엔진으로 치면 회전수가 낮은 대신 실린더의 스트로크가 긴 디젤처럼..
  • machine word align이 맞지 않은 메모리 주소의 값을 fetch하는 것을 굉장한 비효율(여러 클럭수 소모)을 감수하고라도 CPU 차원에서 아무 문제 없이 잘 처리해 준다. 요즘 CPU 같았으면 그냥 예외 날리고 끝이었을 텐데.. 이 역시 메모리를 아끼기 위한 조치이다.

레지스터가 부족하면 나중에라도 더 보충하면 되지 않냐고?
레지스터는 추가로 더 꽂기만 하면 되는 메모리가 아니라 CPU 그 자체이다. 그걸 뒤늦게 확장한다는 건 CPU의 아키텍처, 세부 설계와 생산 라인이 다 바뀐다는 뜻이다. 컴파일러도 그에 맞춰 바뀌고 프로그램도 몽땅 다시 빌드되어야 추가된 레지스터 덕을 볼 수 있다. 사람으로 치면 가방 크기를 더 키우는 게 아니라 생물의 유전자 차원에서 손의 크기, 손가락 개수를 더 키우고 늘리는 것과 같은 엄청난 변화이다.

x86이 너무 지저분하다는 건 제조사인 인텔도 누구보다 잘 알고 있었기 때문에 과거 2000년대 초, 64비트 CPU를 내놓는 김에 애플처럼 하위 호환성을 싹 버리고 현대적인 디자인 트렌드를 따라 과감한 물갈이를 하려 했다.
마소 역시 새천년 Windows 2000에 맞춰 64비트 에디션을 당당히 내놓으려고 벼르고 있었다. Windows SDK 헤더 파일에서 INT_PTR, INT64 이런 typedef가 등장하고 GetWindowLong이 GetWindowLongPtr로 감싸진 게 이 시기의 준비 작업이었다.

하지만 모두의 예상을 깨고 IA64 Itanium라는 새 아키텍처는 CPU와 컴파일러 개발이 제대로 되지 않고 호환성도 안습했기 때문에 철저히 망하고 실패했다.
결국 지금은 기존 x86을 그대로 수용하면서 Itanium보다 훨씬 더 현실과 절충한 x86-64라는 다른 아키텍처를 기반으로 64비트 컴퓨터가 쓰이게 됐다. 이 아키텍처는 인텔이 아니라 경쟁사인 AMD가 최초로 개발했다.

Windows 2000은 과거 NT 3~4 시절에 지원했던 한물 간 구형 CPU들의 지원은 다 끊었고(Alpha, PowerPC, MIPS 등), IA64는 베이퍼웨어이고, 지금 같은 ARM이나 x64는 아직 안 나왔다 보니 NT로서는 이례적으로 사실상 x86 전용으로만 출시되어야 했다.

그런데.. 인텔 x86이 저렇게 메모리 아끼려고 CPU 본연의 효율까지 희생하면서 헝그리하게 설계된 건 과거 PC의 역사를 살펴보면 충분히 이해가 된다.
32비트 80386 CPU가 이미 1985년에 개발됐는데도 Windows NT, OS/2 같은 이상적인 32비트 운영체제의 도입과 보편화가 10년 가까이 너무 늦었고 Windows 9x 같은 요물이 몇 년간 쓰여야 했던 이유는 32비트 가상 메모리를 운용하고도 남을 정도로 컴의 메모리가 충분치(못해도 수~십수 MB) 못했기 때문이다. (CPU 말고 그래픽 카드는 1987년에 VGA가 개발되자 못해도 2~3년 안으로 프로그램들이 다 지원하기 시작함)

64비트로 넘어갈 때도 마찬가지다. IA64가 개발되던 1990년대 말엔 아직 가정용 컴의 메모리는 100~200MB대에 불과했다. 32비트를 벗어나야 할 이유가 전혀 없었다. 64비트 CPU는 대용량 데이터 처리 분야에서 속도가 좀 더 올라갈지는 모르지만, 같은 명령과 데이터를 수행하더라도 메모리 소모가 훨씬 더 많아지는 건 피할 수 없었다. 이러니 가정용 PC에서 64비트의 대중화는 Windows 2000/XP 시기는 어림도 없고, 본격적으로 램 용량이 4GB를 넘어선 2000년대 후반 Vista/7급은 돼서야 이뤄지게 됐다.

Posted by 사무엘

2017/12/11 08:31 2017/12/11 08:31
, ,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1436

Trackback URL : http://moogi.new21.org/tc/trackback/1436

Comments List

  1. 비밀방문자 2017/12/11 18:28 # M/D Reply Permalink

    관리자만 볼 수 있는 댓글입니다.

    1. 사무엘 2017/12/11 18:36 # M/D Permalink

      우와.. 펫졸드 아저씨가 Windows 프로그래밍 책만 썼는 줄 알았는데,
      역시 올드 타이머 프로그래머답게 밑바닥에서 컴퓨터라는 기계가 밑바닥에서 처음부터 만들어져 온 과정을 고찰한 입문서도 몇 년 전에 썼구나?
      아주 흥미로운 내용일 것 같고 나도 책 내용이 궁금해진다? 우와아앙??

Leave a comment

다음 버전 개발 근황

날개셋 한글 입력기는 2018년 3월쯤 완성 목표로 9.3 버전이 개발 중이다.
프로그램의 전체 소스 코드가 이제 8만 줄을 돌파했다. 참고로 7만 줄은 2015년에 8.2 버전을 개발할 때 달성됐으며, 6만 줄은 2011년에 6.0 버전을 개발하는 과정에서 달성되었다.

※ 버그 수정

1. 후보 변환 관련 문제

지난 9.0과 9.1이 기능 추가 말고 '개선' 사항이란 게 없다시피했기 때문에, 이제 이 프로그램은 기존 기능들이 충분히 안정화가 됐다고 여겨졌다. 그래서 본인은 오랫동안 안심하고 새 기능 구현에만 집중하면 되겠다고 생각했다.

그러나, 얄밉게도 9.1을 공개한 지 얼마 되지 않아 후보(한자) 변환 쪽에서 총체적으로 꽤 난감한 버그가 발견되었다. 옛한글 내지 미완성 한글처럼 내부적으로 단일 코드 포인트로 표현되지 않는 한글을 조합 중인 상태에서 한자 키를 눌러 보면 된다.
'제1후보 변환' 기능에 문제가 있어서 "마지막 낱자(from) + 아무 후보가 없는 상태(to)"로 후보 선택창이 이상하게 뜬다.

사용자 정의 후보에서 from을 옛한글이나 미완성 한글로 지정하더라도 조합 중에는 변환이 되지 않는다.
그리고 조합을 마치고서 post-mortem 변환을 하더라도 cursor 이동 계산이 이상하게 돼서 글자가 정상적인 위치보다 앞에 삽입 되는 식의 오동작이 발생한다.

이건 후보 변환 관련 버그 수정이 마지막으로 행해졌던 8.9시절부터 계속 남아 있었던 문제로 보인다. 9.0이나 9.1때도 버젓이 있었던 문제이다. 그게 지금까지 왜 발견하지 못하고 있었는지, 버그인지 아니면 아예 미구현 미완성이었는지, 왜 그때 코드를 이 따위로 작성했는지 자괴감이 든다. 뭐, 버그를 발견 즉시 사살하긴 했다.

2. MS Word에서의 수식 중복 수행 문제

그리고, MS Word에서 특정 상황 조건이 만족되었을 때(가령 bksp를 누른 뒤), 글쇠를 한 번만 눌렀는데 그 글쇠에 대한 수식이 두 번 수행되어 오동작이 발생하는 문제를 해결했다.
이 문제는 3년 전에 나온 7.7 버전에서 다뤄진 적이 있었지만 그 당시의 해결책이 온전하지 못했다. 추가적인 문제는 내가 발견한 건 아니고 사용자의 제보를 통해 파악했다.

기술적인 관점에서 보면, MS Word와 워드패드는 TSF 인터페이스를 잘 지원하는 프로그램이긴 하지만 얘들만 글쇠를 좀 이상하게 인식하고 요청하는 문제가 있어서 이들 프로그램에 대한 보정이 필요했다. 워드패드는 혼자 다른 프로그램들과 정반대의 순서로 key 입력을 전해 주며, Word는 순서는 문제가 없는데 동일한 key 입력을 중복 전달하는 경우가 있다.

이게 버그가 아니라 사용자가 진짜로 같은 key를 반복해서 누른 것일 수도 있기 때문에 보정도 앞뒤 상황을 봐 가면서 조심스럽게 해야 한다. 여러 모로 골치아프다.
게다가 중복 전달을 2중이 아니라 아예 3중으로도 하는 경우가 있는데, 내 프로그램은 이에 대한 대비는 돼 있지 않았다. 이를 확인하여 개선했다.

※ 보조 입력 도구 기능 추가

그럼, 버그 수정 내역 말고 기능 추가 내역을 소개하겠다. 이번 9.3도 지난 9.1과 마찬가지로 '보조 입력 도구' 가 새로운 것들이 추가되고 있다. 특별히 한글 입력기(문자 생성기)의 내부 상태를 시각적으로 진단· 확인하는 데 도움이 되는 것들이다.

1. 수식 계산 기록

이건 꽤 이색적인 보조 입력 도구이다. 얘를 띄우고서 글자판을 바꾸거나 한글을 입력하거나 각종 기능을 조작하면 그 과정에서 내부적으로 실행된 글쇠배열, 오토마타 등의 수식이 화면이 쭉 뜬다. 그 수식 중 하나를 클릭하면 어느 설정에서 유래된 수식이고 초기에 공급된 변수값들이 무엇이 있는지, 실행 후에 대입 연산으로 인해 변경된 변수가 있는지, 수식의 계산 결과는 무엇이 나왔는지가 화면 우측에 조목조목 나타난다.

사용자 삽입 이미지

그러니 이 기능을 사용하면 내가 만든 입력 설정이 기대했던 대로 동작하지 않을 때 수식과 변수에 무슨 문제가 있는지 추적을 아주 편리하게 할 수 있다.
수식은 날개셋 한글 입력기의 설정을 기술하는 핵심 구성 요소이다. 하지만 이게 어떤 방식으로 동작하는지를 사용자에게 시각적으로 알기 쉽게 보여주는 편의 기능이 없어서 사용이 불편했던 게 현실이다. 이 입력 도구는 그 불편을 크게 개선해 주리라 기대된다.

2. 내부 입력 상태 표시

얘도 '수식 계산 기록'와 비슷하지만 관점이 미묘하게 다른 입력 도구이다. 조합을 만들어 낸 문자 생성기의 내부 상태만을 표시해 줄 뿐 자신이 뭔가 입력 기능을 제공하는 건 없는 read-only 도구이다. '내부 입력 상태'는..

사용자 삽입 이미지

(1) 조합 문자열이 생기면 그 조합을 생성한 주체, 문자 생성기의 오토마타 상태 번호, 그리고 조합의 종류를 표시한다. 대부분의 경우 조합을 소유한 주체는 그냥 지금 키보드 입력을 담당하는 입력 스키마이지만, 자체적인 문자 생성기를 가진 보조 입력 도구가 주체가 될 수도 있다(휴대전화, 한손 입력기 같은..). 조합의 종류도 한글 또는 고급 입력기의 사용자 정의 조합 이렇게 두 종류가 존재한다.

(2) 입력 스키마 휘하에 있는 사용자 변수들이 현재 갖고 있는 값들을 출력한다. '수식 계산 기록'은 수식 계산이 행해질 때마다 각각의 계산 내역들을 '목록' 형태로 관리하며, 프로그램이 제공하는 대문자 변수의 값도 다 출력해 준다. 그 반면, 얘는 모든 처리가 끝난 뒤에 글쇠배열과 오토마타 등이 공유하는 소문자 사용자 변수들의 최종적인 값만 실시간으로 업데이트 하여 보여준다. 사용자 변수의 변화만 추적할 때는 '내부 입력 상태 표시' 도구를 사용하는 게 더 편리할 수도 있다.

(3) 그리고.. 현재 발동된 타이머들을 모두 표시해서 "지금으로부터 타이머 N이 1.x초 후에 발동 예정" 이거 카운트다운을 실시간으로 보여준다. 한 타이머가 반복해서 작동되었으면 hit 횟수까지 카운트 해 준다. 물론 타이머를 발동한 근거 수식이나 그때 입력된 날개셋문자를 확인하려면 '수식 계산 기록' 도구의 도움을 받아야 하지만, 타이머의 작동 현황을 실시간으로 파악하려면 이렇게 다른 관점에서 만들어진 입력 도구를 같이 사용하는 것이 좋다.

※ UI 개선

1. '한글 표현 방식' 탭의 변신

외부 모듈(+ 입력 패드)에서 날개셋 제어판을 열면 시스템 계층에 잘 알다시피 '한글 표현 방식'이라는 거창한 탭이 제공되는데..
한번 만들어 놓은 뒤부터 오랫동안 불변이던 이 탭이 이번에 정말 획기적으로 크게 달라졌다.

(1) 처음 열었을 때는 내정값 말고 나머지 복잡한 설정들은 보이지 않게 디자인을 바꿨다. "세부 옵션 보기"를 클릭해야만 이전부터 있던 옵션들이 나타난다.
다만, 이전에 사용자가 맞춰 놓은 설정이 내정값 중 하나로 떨어지는 상태가 아니었다면 역시 처음부터 detailed view 상태로 대화상자가 뜬다.

사용자 삽입 이미지

(2) 그리고, 이 방식의 옛한글을 표시하려면 무슨 글꼴이 필요하네 뭐네 장황하고 잡다하던 설명을 다 집어치우고.. 그냥 백문이 불여일견을 구현했다.
자체 비트맵 글꼴로 예문을 레퍼런스로 제시한 뒤, 바탕, 맑은고딕 등 사용자의 컴에 있는 주요 글꼴로 지금 옵션대로 옛한글을 찍은 결과를 직접 보여주게 했다~~!

아.. 속이 다 후련하다. 이 대화상자를 진작부터 왜 이렇게 만들 생각을 안 했나 모르겠다.
물론 지금은 무려 2018년이 코앞이고 옛한글 표현 기술은 유니코드 5.2 표준이 완전히 정착했다. 이제 한글 표현 방식을 변경하는 건 "현대 한글 전용" 아니면 "유니코드 5.2" 내정값 이 둘밖에 없으며, 나머지는 그냥 legacy일 뿐이다.

그러니 이 '한글 표현 방식' 탭은 제공되는 옵션들을 처음부터 사용자에게 몽땅 미주알고주알 보여줄 필요가 없으며, 특수한 이유가 있는 게 아니라면 이건 오히려 건드리지 않는 게 좋다고 먼저 안내해야 한다. (1)은 이런 생각을 구현한 것이다.

지금 이 기능을 새로 구현한다면 '한글 표현 방식'을 선택하는 건 별도의 탭을 만들지 않고 시스템 계층의 다른 대화상자에다가 콤보 상자와 버튼 하나로 간단하게 구현됐을 수도 있다.
하지만 이게 처음 도입된 건 날개셋 4.x대 후반, 2007년인가 08년경이었기 때문에 아직 그럴 상황이 아니었다. 유니코드 5.2가 정식 제정되기 수 년 전이었으며, 한양 PUA나 유니코드 1.1 같은 절충안이 여전히 유효하던 때였다. 그러니 무슨 방식을 선택하느냐에 따라서 주의 사항을 출력할 것이 많기도 했다.

이번에 새로 구현된 미리보기 기능은 스크린샷에서 보다시피 현대 한글 자모와 글자, 유니코드 1.1 수준의 자모와 글자, 한양 PUA 문헌에 있는 옛한글과 그렇지 않은 옛한글, 유니코드 5.2 전용 옛한글을 일목요연하게 찍어서 보여준다.
그러니 사용자는 낱자들이 풀어지거나 깨지거나 벌어지지 않고 레퍼런스 렌더링인 비트맵 글꼴과 가장 비슷하게 찍히는 글꼴을 찾아서 그걸로 옛한글을 입력하면 된다.

2. '코드 번호로 변환' 텍스트 필터의 UI 변화

날개셋 한글 입력기에는 '코드 번호로 변환'이라는 텍스트 필터가 있어서 문자를 유니코드 또는 여러 multibyte 인코딩 번호로 풀어 쓰거나 그걸 반대로 재합성하는 기능을 제공했다. 리드미를 찾아보니 8년 전의 5.31 때 첫 도입되었는데, 임의의 유니코드 문자열을 소스 코드나 URL로 풀어 써야 할 때 무척 유용하게 활용 가능한 기능이다.

사용자 삽입 이미지

문자를 숫자로, 또는 숫자를 문자로..
그리고 유니코드 코드 포인트, 또는 특정 인코딩으로.. 이 2*2=4가지 변환을 모두 지원한다.
문자를 유니코드 번호로 변환하는 기능은 어느 문자를 변환할지 수식, 문자 코드 페이지(이 코드 페이지에 없는 것), 글꼴(이 글꼴에 없는 글자) 이렇게 세 조건 중 하나로 지정할 수 있다. 그렇기 때문에 별도의 '조건' 대화상자를 여는 버튼이 지금까지 있었다.

그러던 것이 다음 버전부터는 조건 대화상자가 없어지고 그 조건이 동일 대화상자 화면의 아래에 바로 표시된다. 단계가 더 간단해졌다. 위의 스크린샷에서 보는 바와 같다.

그리고.. 문자를 유니코드로 바꾸는 것 말고 인코딩 바이트로 바꾸는 기능에도 "추가로 변환할 문자"를 지정하는 입력란이 추가되었다.
이 기능은 아스키 127번 이하의 문자는 코드값이 불변이기 때문에 0x나 %로 변환을 하지 않는다. 한글· 한자처럼 진짜로 변환해야 하는 문자, 숫자나 접두사와의 혼동을 피해야 하는 문자만 변환해 준다.

하지만 문자열을 URL 같은 데에 전달할 목적으로 변환하다 보면.. +, &, ?처럼 특수한 용도로 예약된 문자도 강제로 변환해야 할 때가 있다. 유니코드 번호로 변환하는 기능이야 수식을 지정할 수가 있지만, 여기서는 문자의 종류가 끽해야 몇십 종류밖에 안 되니 굳이 수식을 넣을 필요는 없고, 부득이하게 강제로 번호로 변환해야 하는 문자를 사용자가 수동으로 지정할 수 있게 했다.

이런 자그마한 기능 추가와 함께 UI 개선, 소스 코드 리팩터링도 같이 진행하니 굉장히 훌륭한 결과가 나왔다. 변환 형태 4가지를 선택하면 그 아래의 화면은 네 가지가 하나도 같은 게 없이 제각각 동적으로 바뀐다. '유니코드 번호를 문자로' 바꾸는 기능이 옵션이 제일 적어서 썰렁하다. '번호 표현 형태'를 고르는 것밖에 남지 않기 때문이다.

※ 나머지 얘기

1. 사소한 변화들

데이터: 9.0에서 첫 도입되었던 24픽셀 옛한글 글꼴이 외형이 지금보다 더 예쁘게 보이게 일부 수정· 개선되었다. 그리고 제공되는 비한글 입력 예제인 Qwerty/Latin Ext가 최신 유니코드를 기준으로 후보 데이터가 더 방대해졌다. 이것들은 정 재민 님께서 수고해 주셨다.

타자연습: 큰 기능 추가는 없으나, 입력기의 API 구조 변경의 영향을 받아서 타자연습도 새 릴리스가 나오긴 할 것이다. main 화면에서 Alt+1~6을 누르면 '시작'부터 '통계' 탭까지 곧장 이동하게 비밀 단축키를 추가했다. 마우스 없이 키보드만으로 프로그램을 사용하기가 좀 더 편리해질 것이다.

2. 고민: 보안 프로그램과의 충돌 문제

날개셋 한글 입력기가 보안 프로그램과 충돌하는 건 2000년대 중반쯤부터 인터넷 뱅킹 사이트 위주로 신고가 들어오곤 했다. 그때는 ActiveX 형태로 동작하면서 키보드 드라이버 계층에서 날개셋으로 전달되는 입력을 차단하여 내 프로그램 동작을 먹통으로 만드는 게 문제였다. 즉, 프로그램이 아닌 사이트가 문제였다.

또한, 그때는 엄밀히 말해서 3rd-party IME를 쓰는 게 문제가 아니라 세벌식을 쓰는 게 문제인 경우도 있었다. 한글을 입력하라고 알파벳 글쇠만 허용해 놨는데 세벌식은 4단 숫자와 기호 자리까지 사용하니 그것만으로 충분치 못한 것이다.

요즘은 온라인 게임에서 내 프로그램이 잘 동작하지 않는다는 문의가 종종 들어온다. 조합이 덧난다거나 하는 사소한 문제가 아니라 (1) 아예 글쇠가 인식되지 않고 한글이 아닌 영문만 입력된다거나, (2) MS IME로는 문제가 없는데 날개셋만 그런다면 그건 내 프로그램에서 딱히 해결책이 없을 가능성이 90% 이상이다. 해당 게임, 더 정확히는 그 게임이 사용하는 보안 솔루션이 날개셋 한글 입력기의 동작을 차단하지 않아야 한다.

사실, 내 프로그램이 디지털 서명이 없어서 각종 백신이나 보안 프로그램으로부터 의심받는 것도 문제이긴 하다. 현재로서는 뾰족한 대책이 없어서 그냥 넘기고 있지만, 이 때문에 사용자의 불편이 크다면 어찌 해야 할지 고민된다. 요즘은 안 그래도 어지간한 프로그램들은 웹브라우저에서 몽땅 띄우고 네이티브 프로그램의 다운로드와 설치는 점점 기피되는 추세인데, 이런 불편까지 끼치는 것은 참 민망한 일이 아닐 수 없다.

Posted by 사무엘

2017/12/08 08:36 2017/12/08 08:36
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1435

Trackback URL : http://moogi.new21.org/tc/trackback/1435

Leave a comment

일본을 이기는 법

* 예전에 썼던 일본에 대한 생각 글 및 기업 관련 일화 글과 함께 읽을 것을 권한다.

1. 학문· 기술 업적과 제품 시장 점유율로 이긴다. (100점)

2차 대전 이후의 국제화 세계화 자본주의 개방 경쟁 시대에 이거야말로 남의 나라를 합법적으로 제일 수준 높게 이기는 방법이다. 예전 글에서 소개한 적이 있듯이, 전범 기업인 미쓰비시를 쳐바르고 기술 종속 관계를 역전시킨 현대 자동차라든가, 반도체 분야에서 이름은 모르겠다만 일본 기업들을 쳐바른 삼성전자, LG전자 등등..
이것만 알아도 되도 않은 이상한 반기업 구호들 반 이상은 필터링된다. 이공계가 세상을 바꾼다.

2. 문화 예술로 이긴다. (50점)

겨우 한류 스타 욘사마가 어떻고 하는 것만 얘기하는 게 아님. 그야말로 사람들 정신 세계 전반을 점령하는 것을 말한다. 위의 100점짜리와는 분야가 굉장히 다르고 별 것 아니어 보이지만 그래도 중요하다. 이것에 대한 우려 때문에 우리나라가 일본과 경제 협력을 위한 재수교는 무려 1965년에 했어도, 대중문화 개방은 90년대 말이 다 돼서야 성사됐다.
내 한글 입력기는 비록 기술 쪽으로 최첨단 극치를 추구하지는 않지만, 나름 이 바닥을 기여하고 공략하는 것을 목표로 하고 있다. 예술은 아니지만 문화에는 해당한다.

3. 운동 경기에서 이긴다. (30점)

열심히 노오오력해서 한일전에서 일본 이겨 주는 것도 아주 합법적이고 좋은 방법이다. 하지만, 스포츠는 경기 당시에 짜릿함 카타르시스를 주는 것 외에 우리 일상생활에 딱히 영향을 끼치는 건 아니다.
또한, 축구 한일전이 벌어질 때에만 열혈 민족주의 애국자이고 다른 상황에서는 자기 나라를 전혀 사랑하지 않는 이상한 사람들도 많다. 그들에게 대한민국이라는 나라나 태극기는 도대체 무슨 의미를 지닌 존재인 걸까?

4. 목소리와 키보드 배틀에서 이긴다. (5점)

국가관 역사관이 이상한 사람을 키배로 제압하고 산업화해 주고, 어디에 일본해가 어떻고 독도가 어떻고 하는 곳에 득달같이 달라붙고, 일본 정치인들 망언을 규탄하는 시위 벌이는 건..;; 들이는 시간에 비해서 그렇게 생산적이지는 않아 보인다.

5. 국민성, 공중도덕 등으로..

이건 이기는 법이라기보다는 지지 않는 법의 범주에 드는 것 같다.

6. 전쟁에서 이긴다? (??)

가능하지도 않고 그래야만 할 필요도 의미도 없음.
한· 일은 정치 이념 프레임이 동일한 나라이며, 예측 가능한 미래에 서로 전쟁 벌일 확률은 남북한이 전쟁 벌일 확률보다는 넘사벽급으로 낮다.

한일전 하니까 옛날 일화가 하나 떠오른다.
뭐, 예전에 비해 반일 감정이 많이 옅어진 편인 지금도 한일전이라 하면 일단 나라의 자존심이 걸려 있고 그야말로 절대로 져서는 안 되는 싸움이라 여겨진다. 하지만 진짜 한일전의 원조는 먼 옛날 1954년, 우리나라가 FIFA 월드컵에 최초로 참가하던 시절에 벌어졌다(그 당시 스위스 개최).
우리로서는 6· 25 전쟁이 끝난 지 얼마 안 됐고, 스포츠 분야에서 해방 후 최초로 앙숙 일본과 맞장을 뜨게 됐다. 1953년에 치러진 아시아 지역 예선전이다.

해방된 지 아직 10년이 채 안 되었으니 분위기가 얼마나 비장했을까?
씅만 리 할배 대통령은 승부에 대한 극심한 중압감과 부담감 때문에 처음엔 이 경기 자체를 원하지 않았을 정도였다. 그냥 월드컵 출전을 포기하고 말지, 일본놈들과는 상종을 하고 싶지 않았다.

원래 경기는 우리 홈그라운드에서 한 판, 일본으로 원정 가서 한 판씩 하는데 “쪽발이 왜놈들을 한국 땅에 들어오게 할 수 없다”라는 똥고집, 그리고 그 와중에 일본이 우리를 이겨 버리기까지 했을 때 뒷감당을 할 수 없다는 걱정이 반반씩 할배의 머리를 압박했다.
(하긴, 일제 강점기 때 일본 정부와 협력해서 반인륜 범죄를 저지르는 데 가담하고 부역한 외국인은 우리나라에 입국할 수 없다고 지금까지도 출입국 관리법에 명시돼 있긴 하다. 뭐 이젠 그런 사람들은 거의 다 죽고 없겠지만..)

뭐 어쨌든, 일본 선수들이 한국으로 올 수 없으니 우리 선수들이 두 판 모두 일본에 가서 경기를 치르게 됐다. 출정식 때 할배 각하는 친히 선수들에게 “이기지 못하면 살아서 돌아오지 마라 / 졌다가는 국민 세금으로 배 탈 생각일랑 말고 대한해협을 헤엄 쳐서 귀국해라” 이런 급의 공포스러운 막말 훈화를 했다는 카더라가 전해진다. 아니면 축구 협회 대표와 선수팀 감독이 각하를 끈질기게 설득하는 과정에서 저런 맹세를 했다고도 한다.

하지만 저런 처절한 배수진 하에서 스포츠계의 합법 도핑인 반일로이드가 약발이 제대로 적중했다..;; 우리나라는 1차전에서 5:1로 일본을 압도적으로 꺾었으며, 2차전에서도 2:2 무승부를 달성해서 무난히 본선 진출에 성공했다! 이때야 스포츠 분야의 극일 가중치가 지금 같은 30점이 아니라 당연히 그 이상이었을 것이다. 독립 주권 국가로서 한국이 일본을 당당히 이겼으니까.

뭐, 본선 가서는 헝가리에게 9:0, 터키에게 7:0으로 지고 광탈하긴 했지만, 그건 너무나 열악한 여건 하에서 첫 출전을 하고도 정말 혼신을 다해서 얻은 결과였다. 10몇 대, 20대 0으로 지지 않은 것만으로도 대단했던 값진 투혼이요 성공적인 실패, 위대한 패배였다. (그리고 일본만 이겼으면 됐고 그것만으로 목표 달성이지, 나머지 결과는 어차피 아오안이었을 것이다..;; )

이 승만은 정말 쥐뿔도 힘 없는 가난한 나라 처지에서도 그래도 미국을 최대한 이용해서 일본을 상대로 갑질을 하고 반일 노선을 고집했다. 평화선에, “대마도 내놔”에, 재일 교포 북송에 결사 반대하여 일본 적십자사 테러 시도에, 그것도 모자라서 왜관 발언은 최고의 압권이었다.
“지금 우리가 아무리 전쟁 중이고 위급하다지만, 감히 일본놈들이 우리 집안 내부 싸움에 개입하려 든다면(심지어 남한을 돕는 것도 포함) 우린 일본놈들부터 죽이고 나서 괴뢰군을 쏘겠다.

하긴, 이 할배의 입장에서는 일본이 유엔군 병참기지가 돼서 경제적으로 어부지리 덕을 보고 있는 것조차도 차마 눈꼴 시려 못 볼 지경이었을 게다.

저 때야 해방된 지 얼마 안 됐으니 그렇다 치지만, 가만히 생각해 보니 지난 2002년 월드컵은 개최 장소도 이례적으로 한일 공동 개최로 귀착됐었다. 20여 년 전에 이거 개최지 결정하던 과정도 내 기억으로 분위기가 장난 아니게 험악했다. 둘 중 한 나라 단독 개최로 결정 났다면 무슨 불미스러운 일이 벌어질지 알 수 없었다. 그래, 한국과 일본은 뭐 그런 사이이다.

하지만 감정은 감정이고, 이성적으로 분별할 건 따로 분별해야지..
까놓고 말해서 일본이 평화 헌법을 건드리거나 심지어 자위대를 군대로 승격하는 것보다, 당장 코앞에 있는 미친 또라이 국가의 핵탄두가 실험을 거듭하면서 위력이 더 강력해지고, 미사일의 사거리가 갈수록 더 길어지는 게 훨씬 더 위험한 일이다!

지금은 20세기 초 같은 제국주의 군국주의 이념이 세계를 지배하는 시대가 아니다. 일본의 작은 또라이짓에 대해서는 난리를 치고 발광을 하면서, 바로 옆에 현존하는 훨씬 더 직접적인 위협에 대해서는 아무 말도 없고 방어 체계를 구축하지 말라고 X랄인 것은 정말 머리가 정상적인 상태가 아니다.

쟤들은 종북들을 이용해서 남조선을 살살 삥뜯거나 한반도에서 미국의 영향력을 완전히 떼어 놓기 위해서 핵을 만들 뿐이다. 터뜨려서 자폭하거나 심지어 미국을 공격하기 위해서 핵을 만드는 게 절대로 아니다. 그게 불가능하다는 건 걔네들도 잘 알 것이다.

본인 역시 지금 당장 더 절박하고 시급한 문제이기 때문에 평소에는 종북 쪽을 더 비판하고 까며 지낸다. 하지만 우파가 반일· 극일 분야도 좌향좌들보다 훨씬 더 건전하게 실천하고 있다는 것을 본인은 행동으로 입증하고 싶다. 사상과 행적 모든 면이 우월하다는 것을 말이다.

Posted by 사무엘

2017/12/05 08:33 2017/12/05 08:33
, , , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1434

Trackback URL : http://moogi.new21.org/tc/trackback/1434

Leave a comment

1. 트렁크에 싣는 물건들

차의 접지력을 위해서 일부러 무겁게 만드는 경우가 아니라면, 어지간해서는 트렁크에 쓸데없는 짐을 싣지 말고 차를 가볍게 유지하는 게 연비 운전의 정석이다. 하지만 평소에 차의 트렁크에 늘 실어 놓을 만한 물건도 전혀 없는 건 아니다. 생각해 보니 다음과 같이 인간 편의용과 차량 비상용으로 범주가 나뉜다.

  • 어디 여행 간 뒤, 현장에서의 인간 편의용: 돗자리, 담요(비행기 담요 같은..), 우산, 슬리퍼, 손전등, 식수, 나무젓가락, 종이컵, 상비약, 휴지/티슈
  • 차량 비상용: 소화기, 비상 삼각대, 경광봉과 건전지, (간단한 공구류와 스페어 타이어는 당연히..)

평소에는 워낙 조용하게 달리니 잘 모르겠지만, 자동차는 엔진 내부가 매우 뜨거우며 화재의 위험이 상존하는 물건이다. 굳이 냉각수 부족과 엔진 과열 때문이 아니어도, 운 나쁘게 엔진룸 속에 끼어들어간 종이· 나뭇잎 같은 이물질이 발화점 이상의 열을 받아서 불이 붙고, 그게 차량의 화재로 이어질 수 있다. 식당도 굳이 누전이나 가스 누출 같은 일이 없이, 환풍기에 낀 사소한 기름때나 먼지만으로 불이 날 수도 있는 것처럼 말이다.

또한, 큰 교통사고가 난 뒤에는 연료가 새서 케바케로 불이 나기도 한다. 승용차의 경우 엔진이 있는 앞쪽과 연료 탱크가 있는 뒤쪽 모두 안심할 수 없다.
이럴 때 소화기를 신속하게 꺼내서 연기와 불꽃이 최초로 모락모락 피어나는 곳을 적절하게 초기 진화해 주지 못하면.. 엔진 부분만 교체하고 끝날 것을 발만 동동 구르다가 차량 전체를 홀랑 태워먹고 전체 폐차라는 비극을 야기할 수 있다.

자동차는 뼈대만 쇳덩이일 뿐, 시트나 도색 등은 온통 가연성 화학물질이며, 불타면서 유독가스를 내뿜는 공해덩어리 그 자체다. 불 나서 좋을 것 하나도 없다.
말이 길어졌는데, 어쨌든 PC에 보안 업데이트가 필요한 것만큼이나 차량에는 소화기를 비치할 필요가 있다는 말을 하고 싶었다. 사고가 난 뒤에 2차 사고를 예방하는.. (나 여기 있소) 도구들은 두 말할 나위도 없고 말이다. 자동차 학원에서도 이런 물건들의 필요성을 더 진지하게 가르쳐야 하지 않나 싶다.

돗자리나 우산, 슬리퍼 같은 수준을 넘어서 아예 낚싯대· 골프채, 커다란 악기, 자전거 같은 걸 차에다 상시 실어 놓는 건...;; 글쎄, 정말 차를 오로지 레저와 여가용으로만 활용하는 게 아니라면 "화물은 차를 무겁게 할 뿐이야!"를 진지하게 고려해야 할 것이다. 그래도 자전거를 차에다 싣는 게 가능하면 차와 자전거의 활용성이 더욱 커져서 상호 win-win이 되긴 하더라. 차 트렁크도 충분히 커야 하고, 자전거도 접을 수 있는 구조여야 한다.

2. 자동차의 냉각수와 워셔액

자동차의 내부에 집어넣어서 비축하는 액체 중에 연료나 윤활유 같은 기름 계열 말고 '물' 계열 혼합물에 속하는 것은 엔진 냉각수와 와이퍼 워셔액 정도인 것 같다. 전자는 물의 높은 비열이 활용되고 후자는 물의 세척력이 쓰인다.
물론 두 액체의 용도와 성격은 서로 매우 다르다. 워셔액은 유리창이 깨끗하기만 하면 별로 쓸 일이 없는 선택사양이지만, 냉각수는 엔진의 가동과 직접적인 관계가 있는 필수품이다. 워셔액은 세척용으로 조금씩 소모되고 보충이 필요한 소모품인 반면, 냉각수는 누수 같은 이상 현상이 없는 한, 한번 주입해 준 게 반영구적으로 쓰인다는 차이가 있다.

순수한 물은 그리 낮지 않은 온도에서도 금세 얼어 버리며 금속류의 부식(녹)을 초래하기도 한다. 그렇기 때문에 두 액체 모두 부동액과 부식 방지 성분이 첨가된다. 동일하지는 않지만 공교롭게도 알코올 계열 화합물이 첨가되는데, 둘 다 인체에 아주 해로운 독극물이라는 공통점이 있다.

부동액의 첨가 성분인 '에틸렌 글리콜'은 물과 혼합될 경우 어는점을 영하 40도 아래로 크게 낮춰 준다. 성능 하나는 뛰어나지만 그렇다고 이것만 잔뜩 집어넣으면 반대로 물 고유의 냉각 성능이 저하되기 때문에 부동액을 아무리 많이 넣어도 물보다 많이 넣지는 않는다. 그리고 이 에틸렌 글리콜은 독약임에도 불구하고 투명한 외형에 꽤 달콤한 맛과 냄새가 나서 사람이나 동물이 실수로 마시고 훅 가는 사고가 세계적으로 종종 발생한다고 한다.

이거 무슨 농약도 아니고.. 그 맛과 냄새가 어떤지 개인적으로 궁금하다..;; 부동액이란 게 자동차에만 쓰이는 게 아니고 혹한의 건축· 건설 현장에서도 물이 들어가는 곳에 쓰이기 때문이다.
도로의 제설용으로 사용되는 염화칼슘도 물과 섞이면 수용액의 어는점을 역시 거의 영하 52도쯤으로 크게 낮춰 준다. 이 효과로 눈을 녹여 버려서 제설 효과를 낸다. 그러니 나름 제설에다 제습 효과까지 있는 물건인데.. 얘는 이미 짐작한 분도 계시겠지만 부식 문제가 있어서 부동액 용도로는 쓰이지 않는다. 뭐 부동액 얘기는 여기까지 하고..

와이퍼 워셔액은 비록 사람이 마시는 술 같은 액체는 아니지만 소독(?), 빠른 증발, 부동 효과를 위해 역시 알코올이 들어간다. 그런데 단가가 저렴하고 가성비가 뛰어나다는 이유로 메탄올이 들어가기도 한단다.
메탄올은 보다시피 극소량만 인체에 들어가도 신경을 마비시키고 눈을 멀게 하고 궁극적으로 생명까지 잃게 만드는 맹독이다. 선박이나 실험실 같은 데서 술 취한 기분 내고 싶어서 메탄올을 에탄올인 줄 알고 물에 섞어서 들이켰다가 골로 간 사람들.. 역시 없지 않다. 정상적으로 팔리는 술을 구할 수 없거나, 세금 안 붙은 저렴한 알코올을 섭취하고 싶어하는 상황에서 말이다.

2012년에는 워셔액을 술인 줄 알고 마시는 바람에 메탄올 중독으로 숨진 사람이 다윈 상 수상자 중 하나로 뽑히기도 했다! 하지만 이건 고의로 멍청한 짓을 한 게 아닌 단순 실수가 아니냐는 이견과 논란도 있다.

메탄올은 이렇게 입으로 들이키지만 않는다고 해서 장땡이 아니라고 한다. 앞유리에다 워셔액을 분사하는 경우, 메탄올이 소량이나마 기화한 형태로 차내에 유입되기도 한다. 워셔액 제조사들이야 그건 극소량이기 때문에 별로 문제될 게 없다는 입장이지만, 이제 대한 정밀한 임상 실험이 진행된 사례는 아직 없는 것 같다. 정 불안하면 좀 더 비싸더라도 에탄올 성분의 워셔액을 쓰는 수밖에 없다.

3. 차량의 외형과 내부 구조의 차이

트렁크와 객실(cabin)의 구분이 없는 해치백형 차량(SUV 포함)이 공간 활용성이 더 좋은 건 사실이다. 뒷좌석을 완전히 접거나 옮겨서 자전거를 접지 않고 그대로 실을 수 있고, 아니면 사람이 발 뻗고 눕는 공간을 만들 수도 있다.
무척 부러운 면모이긴 하지만, 이런 실용성과는 별개로 본인의 취향은 그래도 트렁크와 객실이 완전히 분리되어 있는 세단이 뭔가 안정적인 느낌이 들고 좋다.

하루는 회사 업무 때문에 짐을(컴퓨터 본체 여러 대 등..) 승용차의 트렁크와 뒷좌석에 이르기까지 잔뜩 실을 일이 있었다. 그런데 이 차는 회사의 이사· 사장급인 높으신(...) 분의 소유였고.. 그래서 대형 후륜구동이었다.
후륜구동은 잘 알다시피 뒷좌석 중앙 바닥이 구동축 때문에 위로 봉긋 솟아 있다. 요것 때문에 짐 싣는 데 의외의 어려움을 겪었던 걸로 기억한다. 그 일을 겪고 나니 뒷좌석 바닥이 그냥 평평한 내 차, 아니 요즘 대부분의 승용차들이 더욱 신기하게 느껴졌다.

하긴, 나 완전 어렸을 때 탔던 포니 택시도 뒷좌석 중앙이 봉긋 솟아 있긴 했는데, 저런 차를 참 오랜만에 다시 구경했다. 포니야 소형차 덩치밖에 안 되지만 아직 기술과 노하우가 부족해서 후륜구동으로 나온 것이다.

포니 1은 해치백처럼 생겼지만 실제로는 객실과 트렁크가 분리되어 있었으며, 트렁크를 열 때도 뒷유리는 고정된 채 아래의 몸체만 들려 올라갔다(4도어 일반 모델 기준). 즉, 사실상 세단이나 마찬가지였다. 해치백은 3도어 쿠페 모델에서 처음 적용되었으며, 그리고 후속작인 포니 2에서 완전히 해치백 형태로 바뀌었다고 들었다.

사용자 삽입 이미지사용자 삽입 이미지

이런 내부 구조 말고 해치백은 세단과 달리 뒷유리에도 와이퍼가 달려 있는 게 특징이다. 뒷면의 유체역학적 구조상 트렁크가 튀어나와 있는 세단보다 뒷유리에 흙먼지가 더 잘 끼기 때문이라고 한다.

4. 자동차의 동력원

(1) 내연기관이 발명되자 처음에는 자동차, 열차, 비행기가 모두 휘발유건 디젤이건 피스톤 왕복 엔진을 동력원으로 사용했다. 그러다가 20세기 중반부터 비행기는 제트 엔진이 대세가 되었으며, 철도 차량은 주 동력원이 전기 모터로 바뀌었다.
덕분에 털털털 붕붕붕~ 이러던 엔진음이 다 바뀌었다. 제트기는 그 특유의 공기 뿜는 소리 덕분에 한때 '쌕쌕이'라고 불렸을 정도이며, 전철은.. 뭐 VVVF 인버터가 도입되면서 완전 전자악기 소리가 나기 시작했다.

결국 오늘날은 자동차만이 왕복 엔진을 꾸준히 사용하고 있다.
왕복 엔진이 배기가스를 내뿜는 건 그냥 연소가 끝난 잔여 찌꺼기를 내보내는 것이기 때문에 엔진 출력과는 무관한 메커니즘이다. 그러나 제트 엔진은 배기가스를 엄청난 고압으로 뒤로 내뿜어서 추진력을 낸다. 자동차와는 앞으로 나아가는 방식이 완전히 다르다.

이렇게 동일한 재료나 부품이 한 기술에서는 그저 그런 존재감인 것이, 다른 기술에서는 동작에 결정적인 역할을 하는 중요한 요소인 경우가 있다.
배터리가 기름 자동차에게는 그냥 객실 전원 공급과 시동 모터+점화 플러그 동작용이지만, 하이브리드나 순수 전기차에게는 차를 가게 하는 동력원 그 자체인 것,
그리고 변속기 오일이 수동 변속기에서는 정말 단순 윤활 기능만 하지만, 자동 변속기에서는 엔진과 바퀴 동력을 중재하는 완전 핵심 매체인 것처럼 말이다. 예전에도 언급한 적이 있지 싶다.

(2) 그리고 자동차가 처음 발명됐을 때 차의 가장 일반적인 형태는 전방 엔진, 후륜 구동인 일명 FR 방식이었다. 그러다가 승용차는 준대형급(대략 3000cc) 이하부터는 FF로 바뀌었고, 버스는 준대형급(35인승) 이상부터는 RR로 바뀌었다. FR은 이제 대형 승용차와 소형 승합차, 또는 크기 불문하고 트럭에서만 유지되고 있다.

(3) 전동차에 가변 전압 가변 주파수(VVVF) 인버터 기술이 있다면, 내연기관 자동차 엔진에도 공기를 흡입· 배출하는 밸브에 가변화 기술이 있다. 엔진 회전수에 따라 밸브의 여닫는 깊이를 지능적으로 조절하는 VVL (lift), 그리고 그 개폐 동작의 시점 자체를 조절하는 VVT (time). 흡기측과 배기측에 shaft를 구분한 DOHC 방식에 이어서 밸브 계통에 또 다른 발전이 이뤄졌다.

그리고 어느 분야건 양과 질, 주기와 강도를 조절하는 변수가 있다. 라디오에는 AM(세기)과 FM(주파수)이 있고, VVVF도 V는 전압(세기)이요 F는 주파수이다. 자동차에도 VVL은 강도이고 VVT는 타이밍이니까 동일한 개념이지 않은가?

5. 차량별 변속기 성향

자동차의 동력 변환 계통으로서 물리적으로 큰 바퀴와 작은 톱니바퀴를 맞물리게 돌아가게 하는 '기어'라는 건 꽤 간단하고 직관적이고 효율적인 수단이다.
그러나 200~300마력짜리 자동차를 넘어서 열차나 거대 건설기계 수준이 되면 미세한 출력 조절을 위해서는 가히 어마어마한 크기의 기어비와 다양한 단계가 필요해지는데, 이건 톱니바퀴만으로 감당할 수 없다. 바퀴가 너무 커지거나 개수가 늘고 무겁고 복잡해진다.

(1) 그래서 철도 기관차는 동력을 일단 변압이 자유로운 교류 전기로 바꿔서 전동기를 돌려서 움직이는 디젤 전기 기관차가 대세이며, 드물게 자동 변속기 같은 유체 토크 컨버터로 동력을 변환하는 차종도 있다. 과거에 다녔던 새마을호 전후동력형 디젤 동차가 이 범주에 속한다.
물론 이것들은 광원에다 비유하자면 직접조명에서 간접조명으로 바뀐 것과 같기 때문에 연비는 톱니바퀴 기어만치 좋지 못하다.

(2) 대형 버스와 트럭은 저 정도로 불가피한 상황도 아니고, 또 연비와 옵션 가격 같은 경제성 문제도 있기 때문에 오늘날까지 여전히 수동 변속기 차량이 대세이다.

(3) 그런데, 이 와중에도 예외적으로 자동 변속기가 기본인 대형 상용차도 있으니 바로 “저상버스”이다.
바닥이 워낙 낮아서 버스 엔진 출력 정도의 동력비를 감당할 기어박스 내지 굵고 긴 샤프트조차(운전석에서 뒤쪽의 엔진까지)도 장착할 수가 없는 관계로 불가피하게 자동 변속기를 쓴다. 변속 명령은 기계 조작이 아닌 전기 신호로 전하고, 실제 변속 역시 톱니바퀴가 아닌 토크 컨버터로 행한다.

사실, 옛날에 버스가 트럭과 별 차이 없는 전방 엔진 방식으로 만들어지던 시절에는 바닥이 왕창 높았을 뿐만 아니라, 아예 구동축이 차체의 아래 중앙을 관통했다. 그래서 고속버스의 경우 바닥 아래의 화물칸까지도 좌우로 서로 단절돼 있을 정도였다.
그때에 비하면 버스가 바닥이 정말 낮아지고 사람이 타고 내리기 좋아진 셈이다. 철도로 치면 고상홈이 도입된 것과 비슷한 변화이다. 이런 차들에 비해 대형 트럭을 타는 건 지금도 거의 등산 수준으로 힘들다..;;

(4) 끝으로, 저런 대형차와는 상극의 체격인 오토바이는 또 반대로 수동이 대세이다.
글쎄, 리터급의 고성능 대형 오토바이라면 모를까 100~300cc대의 그저 그런 모델의 경우.. 그런 엔진 출력과 차체 크기에다가 크고 무거운 토크 컨버터를 장착하는 것부터가 삽질이고, 전통적인 기어박스를 장착하는 게 훨씬 경제적이기 때문이다.
아주 쬐그만 스쿠터는 차라리 CVT가 달리면 달렸지, 어떤 경우든 통상적인 자동차용 자동 변속기 같은 물건이 달리는 일은 없다.

똑같이 공간이 없는데 그 양상이 저상버스와는 다르다는 것이 무척 흥미롭다. 대류권에서는 고도가 오를수록 기온이 내려갔다가 성층권에서는 다시 기온이 올라가는 것 같은 느낌이다.

6. 동력의 취합과 분산

자동차가 굴러가기 위해서는 엔진이 죽어라고 피스톤 왕복운동만 한다고 장땡이 아니라..
여러 개의 피스톤이 균등하지 않은 주기로 만들어내는 불연속적인 힘을 한데 부드럽게 합쳐 주는 플라이휠 같은 부품이 필요하다.
그리고 이 힘을 실제로 회전하는 바퀴에 부드럽게 분산해서 전달하는 주는 차동 기어도 변속기와는 별개의 계층으로서 필요하다. 커브를 틀 때는 커브 안쪽의 바퀴와 바깥쪽의 바퀴가 속도가 달라지기 때문이다. 컴퓨터에다 비유하면 CPU와 램뿐만 아니라 파워 서플라이도 필요하다는 뜻이다.

자전거 중에는 크랭크가 둘 달려서 앞뒤 사람이 모두 페달을 밟을 수 있는 물건이 있다. 이런 자전거는 개인이 구입해서 굴리기보다는 관광지 같은 데에서 대여하는 형태로 사용되는 편이다.
거기에서도 두 사람의 힘이 어떤 형태로 취합되는지 문득 궁금해졌다. 사실 자전거는 페달을 뒤로 밟았을 때 후진하지 않는 것도 신기하고 말이다.

Posted by 사무엘

2017/12/02 08:28 2017/12/02 08:28
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1433

Trackback URL : http://moogi.new21.org/tc/trackback/1433

Leave a comment

1. 오버로딩과 오버라이딩의 관계

요렇게 Func라는 함수를 2개로 오버로딩한 A라는 C++ 클래스가 있다고 치자. 그리고 B는 A로부터 상속을 받았다.

class A {
public:
    virtual void Func(int x) {}
    void Func(int x, int y) {}
};

class B: public A { (...) };

B *ptr = new B;

그렇다면 B는 일반적으로야 너무 당연하게도 A가 갖고 있던 Func라는 함수에 곧장 접근 가능하다. ptr->Func라고 치면 요즘 개발툴은 사용 가능한 함수 후보 2개를 자동으로 찾아서 제시까지 한다.

그런데 B가 Func 중 하나를 오버라이드 하면 사정이 달라진다.

class B: public A {
public:
    void Func(int x) {}
    (...)
};

이전에는 Func라는 이름은 전적으로 부모 클래스의 전유물로 간주되었지만, 오버로딩 형태 중 하나라도 파생 클래스가 오버라이드 한다면 이 이름은 부모의 것과 자식의 것을 구분해야 할 필요가 생기더라.
이제 ptr->Func를 하면 오로지 B에서 갖고 있는 것 하나만 제시된다. 이제는 ptr->Func(1, 5)를 한다고 해서 부모 클래스가 갖고 있는 인자 2개짜리 함수가 자동으로 정적 바인딩 되지 않는다. ptr->A::Func(1, 5)라고 써 줘야 된다.

본인은 이런 기초적인 동작을 보고도 내 직감과는 일치하지 않는 걸 보고 약간 놀랐다. 마치 함수의 리턴값만으로는 오버로딩이 되지 않는 것처럼 저것도 C++이 제공하는 유도리의 한계인가 싶다.
내 의도는 동일한 이름의 함수를 인자의 형태를 달리하여 가상 버전과 비가상 버전으로 둘 다 만들어 놓는 것이었다. 비가상 함수는 부모 클래스 한 곳에다가만 정의해 놓은 뒤, 받은 인자를 보정하여 가상 함수 버전을 호출해 주는 고정된 역할을 한다.

그런데 이름을 동일하게 해 놓으니 파생 클래스에서는 직통으로 호출할 수가 없어서 결국 이름을 다른 걸로 바꾸게 됐다. 이런 것도 마치 생성자나 소멸자에서 가상 함수를 호출하려 한 것과 비슷한 차원의 디자인 실수가 아닌가 싶다.

2. pointer-to-member의 우선순위

C++에서 pointer-to-member 연산자인 .* 내지 ->*는 데이터 멤버를 참조할 때는 별 문제될 게 없지만, 함수를 참조해서 호출할 때는 앞부분을 따로 괄호로 싸야 한다. 즉, (obj.*ptrfn)(a, b) 내지, (pObj->*ptrfn)(x, y)처럼 말이다.
괄호 없이 pObj->*ptrfn(x, y) 이런 식으로 바로 호출이 가능하면 더 깔끔하고 자연스러울 것 같은데, 문법이 왜 이렇게 만들어지게 됐을까?

표면적인 이유는 우선순위 때문이다. 일반적인 구조체 멤버 참조 연산자인 .와 -> 그리고 함수 호출을 나타내는 괄호 연산자는 모두 우선순위가 최상이며, 좌에서 우로 결합한다. 그렇기 때문에 a.b()는 토큰들이 아주 직관적으로 순서대로 해석된다.
그러나 pointer-to-member (이하 P2M) 연산자들은 곱셈 같은 이항 산술 연산자보다만 우선순위가 높을 뿐, 다른 단항 연산자나 괄호 연산자보다 우선순위가 낮다. 그렇게 자신만의 독자적인 우선순위가 있다.

이런 구조 하에서 괄호 없이 a->*b(x,y)라고 쓰면.. ->* 뒤의 b(x,y)가 먼저 해석된다. b는 뭔가 a에 적용 가능한 P2M을 되돌리는 함수가 되는 셈이다. 하지만 P2M 자체도 쓰임이 굉장히 드문 물건인데 하물며 P2M을 되돌리는 함수라..? 일상생활에서 좀체 볼 일이 없을 수밖에 없다. 그러니 저렇게 a->*b를 괄호로 싸지 않고 곧장 함수 호출을 하는 표현도 볼 일이 없어진다.

만약 P2M 연산자의 우선순위가 일반적인 . -> 의 순위와 대등하다면 a->*b(x,y)만으로 (a->*b)(x,y)의 효과를 낼 수 있다. 아까처럼 b 자체가 따로 P2M을 되돌리는 함수라면, 그쪽을 a->*(b(x,y)) 라고 괄호로 싸야 할 것이다.

그런데 b가 데이터가 아닌 함수 P2M을 되돌리는 함수이고, 리턴값으로 또 함수 호출을 해야 한다면 어떻게 될까?
저렇게 가상의 우선순위 체계에서는 a->*(b(x,y))(X,Y)와 같은 형태가 된다.
그러나 지금의 우선순위 체계로는 (a->*b(x,y))(X,Y)가 된다. 이렇게 비교를 하니 아무래도 b만 괄호로 싸는 것보다는 a까지 다같이 괄호로 싸는 형태가 그나마 더 자연스러워 보인다.

요컨대 . ->는 오른쪽 피연산자로는 끽해야 고정된 멤버 이름밖에 오지 못한다. 임의의 변수, 상수, 값이 올 수 없다. 성격이 ::와 비슷하며, 애초에 C++ 말고 오늘날의 다른 프로그래밍 언어들은 아예 . -> ::를 전부 구분 없이 . 하나로 간소화하는 게 트렌드일 정도이다. 오른쪽 피연산자 자체에 함수 호출이 있는지, 전체 결과값을 또 함수로 호출하는지 그런 걸 구분할 일은 없다.

그 반면, .* ->*는 생긴 건 단순 멤버 식별 연산자와 비슷하게 생겼어도 피연산자로는 사실상 아무 값이나 올 수 있다. 그렇기 때문에 뒷부분에 함수 호출 () 파트가 중구난방으로 나열되는 일을 막으려면 P2M은 . ->, 그리고 ()와 동일한 우선순위를 부여해서는 안 된다는 결론이 도출된다.

(a->*b)(x,y)에서 a와 b를 싸는 괄호에는 이런 사연이 숨어 있다. 그래서 얘들은 기존 연산자들보다 우선순위가 한 단계 낮아진 것이지 싶다. 클래스에서 함수 포인터를 되돌리는 operator 함수를 선언할 때 발생하는 다소 난감한 상황과 비슷하다. 저것도 결국은 정석적으로는 안 되고 typedef나 decltype의 도움을 받아야만 선언 가능하니 말이다.

파스칼은 비트 연산자가 논리 연산자의 역할까지 하고 있고 얘가 C/C++과는 반대로 산술 연산자보다 우선순위가 높다. 그렇기 때문에 if 문 안의 (A=B) and (C>5) 이런 항들을 일일이 전부 괄호로 싸야 해서 일면 불편하다. C++의 P2M 연산자의 우선순위는 마치 이런 사연을 보는 것 같기도 하다.

3. MFC와 C 라이브러리의 충돌

C/C++에는 빌드 과정에서 컴파일 에러뿐만 아니라, 현대의 언어에서는 찾기 힘든 개념인 링크 에러라는 게 있다.
이게 단순히 '요 명칭을(주로 함수) 선언만 해 놓고 정의를 안 했네요' 같은 간단한 것만 있으면 세상이 지금보다 훨씬 더 아름다워 보이겠지만, 현실은 그렇지 않다.

C/C++은 바이너리 인터페이스 수준에서 파편화가 매우 심한 걸로 악명높은 언어이다. C++ 함수 인자의 decoration은 말할 것도 없고, 당장 언어가 기본으로 제공하는 C/C++ 표준 라이브러리부터가 그러하다. 디버그/릴리즈, 32/64비트 같은 거야 섞일 일이 거의 없을 정도로 완전히 다른 configuration이니까 그렇다 치더라도 static/DLL, 컴파일러의 제조사와 제품 버전까지도.. 그냥 전부 제각기 따로 논다고 봐야 한다.

표준 라이브러리에 malloc, qsort 같은 영원불변의 간단한 물건만 있는 건 아니기 때문에 말이다. 그러니 다양한 출처에서 빌드된 라이브리러들을 한데 엮다 보면 별의별 링크 에러를 겪을 수 있다.
그래서 컴파일러를 Visual C++로 한정한다 하더라도, 대표적으로 MFC와 C 라이브러리(CRT)부터가 특정 상황에서 서로 부딪칠 수 있다.

MFC와 CRT는 구조적으로 둘 다 DLL 형태로 쓰거나 둘 다 static 링크하는 것만이 가능하다.
그런데 DLL 링크를 할 때는 괜찮은데 static 링크를 하다 보면 가끔 operator new / operator delete라는 메모리 할당/해제 함수가 MFC에도 들어있고 CRT에도 들어있다고.. 심벌 중복 정의라는 LNK2005 에러가 뜬다.

본인의 경우는 MFC를 사용하는 C++ 프로젝트에다가 precompiled header를 사용하지 않는 타 C 코드를 프로젝트에다 넣은 채로 MFC/CRT는 static 형태로 빌드를 시도했을 때 이런 상황에 놓이곤 했다.
operator new/delete 나부랭이야 내가 짠 코드도 아닌데 저 충돌 문제를 도대체 어떻게 해결하면 좋을까..?

이건 그래도 많이 알려지고 유명한 문제인지라 간단히 구글링만 하면 해결 방법이 수십 페이지씩 쭈루룩 뜬다.
/NODEFAULTLIB 옵션을 줘서 링커가 라이브러리들을 암시적으로 자동 공급하지 않게 하고, MFC의 static 링크용 라이브러리인 uafxcw.lib를 다른 라이브러리들보다 먼저 링크되게 하면 된다.

예전에 마소에서 제공했던 Windows 9x 유니코드 API 호환 layer인 unicows 라이브러리를 사용할 때도 링커 옵션을 비슷하게 특이하게 고쳐야 했던 걸로 기억한다. kernel32, user32 같은 통상적인 라이브러리보다 unicows가 먼저 공급 되어야 Windows API 호출이 훅킹 DLL로 갈 테니까 말이다.

아무튼 C/C++은 이런 디테일까지 신경 써야 하는 피곤한 언어이긴 하다. Visual C++의 차기 버전에서는 이런 문제는 자동으로 충돌을 감지하고 해결했으면 좋겠다.

4. 맥용 swscanf의 꼬장

표준 C 함수밖에 쓰지 않은 멀쩡한 x64용 C 코드가 Windows에서는 잘 돌아가던 것이 맥에서는 제대로 동작하지 않았다.
이 경우 원인은 대부분 사소한 곳에 있었다. 파일을 읽고 쓰는 곳에 long이 들어가 있는 게 대표적인 예다. Windows는 long도 int와 동급의 32비트로 보지만 맥에서는 이걸 64비트로 키웠기 때문이다. C/C++은 long도 그렇고 wchar_t도 그렇고.. 파편화가 너무 심하다..;;

단순히 기본 타입의 크기에 대해서는 본인이 예전에도 언급한 바 있다. 그것 말고 최근에는 또 다른 괴상한 사례를 발견했다.
long 문제와도 무관하고 도대체 안 돌아갈 이유가 전혀 없는 코드에서 오류가 발생하고 있었다. 어디에서부터 변수에 잘못된 값이 들어와 있는지를 추적해 보니 문제는 swscanf이었다. wchar_t 크기쯤이야 이미 감안하고 보정을 다 했기 때문에 문제될 여지가 없었다.

"설마 이게 문제이겠나" 싶었는데 설마가 사람을 잡았다. 읽어야 하는 문자열 뒤에 한글· 한자처럼 U+100 이후의 문자가 들어가 있으면 swscanf의 실행이 무조건 실패하고 있었다. 나는 "%X"라고 인자를 줬기 때문에  "FF00 가나다"이라는 문자열이 있으면 프로그램은 '가나다'는 전혀 신경쓸 필요 없고 0xFF00만 읽어 오면 된다. 게다가 'FF00'과 '가나다'의 사이에는 멀쩡히 공백까지 있어서 확인사살을 하고 있다.

그런데 확인을 해 보니 그냥 평범한 'ABC', '^&*%' 따위가 있을 때는 괜찮은데 '가나다'가 있을 때는 실패하더라. FF00의 값을 읽는 것과는 1도 아무 상관 없으며, Windows에서는 당연히 이런 현상 없이 값을 잘 얻어 온다.
이 때문에 swscanf를 쓰던 것을 wcstol로 바꿔서 %X의 역할을 대신하게 해야 했다. wide string 기반의 유니코드이니 무슨 로케일이나 인코딩 같은 설정을 할 필요도 전혀 없는데 swscanf가 왜 쓸데없이 꼬장을 부리는지, 더구나 맥만 왜 이러는지는 알 길이 없다. 살다 보니 별 일을 다 겪었다.

5. 정적 분석 써 본 소감

여느 프로그래머들과 마찬가지로 본인은 요즘 개발툴들이 제공하는 정적 분석 기능을 잘 사용하고 있다. 방대하고 복잡한 코드에 존재하리라고 꿈에도 생각을 못 했던 실수들이 걸려 나오는 경우가 많기 때문이다. 아주 특수한 상황에서 초기화되지 않은 변수가 사용될 가능성, 메모리 내지 리소스 leak이 발생할 가능성 같은 것 말이다.
역시 인간은 어쩔 수 없이 실수란 걸 늘 저지르는 동물이다. 기계가 이런 걸 안 잡아 줬으면 개발자들이 얼마나 고생하게 됐을까? 더구나 내가 직접 만들지도 않고 남이 짠 지저분한 코드를 인계받아서 유지 보수해야 하는 처지라면 말이다.

심지어 내가 머리에 총 맞기라도 했는지, 왜 코딩을 이 따구로 했었나 자괴감이 드는 오류도 있다.
물론 이런 것들은 처음에 코드를 그렇게 작성한 것은 아니다. 나중에 해당 코드가 변경되고 리팩터링이 됐는데 그게 모든 곳에 적용되지 않고 부분적으로 편파적으로만 적용되면서 일관성이 깨진 경우가 더 많다. 예를 들어 리턴값의 타입이 BOOL이다가 나중에 필요에 따라 int로 확장됐는데, 마치 Windows API의 GetMessage 함수처럼 체크 로직은 >0으로 바뀌지 않고 여전히 !=0이 쓰인다면 그런 부분이 잠재적으로 문제가 될 수 있다.

먼 옛날, Visual C++ 4~6 시절에는 프로그램을 빌드할 때 부가 옵션을 줘서 browse 정보를 추가로 생성할 수 있었다. 빌드 시간과 디스크 용량을 매번 추가로 투자해서 이걸 만들어 둬야만 임의의 심벌에 대해서 "선언/정의로 이동, 함수의 Calls to/Called by 그래프 조회" 같은 편의 기능을 사용할 수 있었다.

그랬는데 세월이 흘러서 지금은 C++ 같은 문맥 의존적인 언어조차 심벌 browse 기능 정도는 IDE의 백그라운드 컴파일러로 실시간으로 다 가능하고 최신 정보가 수시로 갱신되는 지경에 이르렀다. 그 대신 지금은 빌드 때의 추가적인 액세서리에 해당하는 것이 바로 '소스 정적 분석'이 된 거나 마찬가지이다. 단순히 기계어 코드를 생성하는 빌드보다 시간이 더 걸리는 대신, 통상적인 너무 뻔한 경고보다 훨씬 더 자세하고 꼼꼼하게 소스 코드에서 의심스러운 부분을 지적해 주는 것이다.

6. C++ 디버깅

하루는 회사에서 Visual C++ 2015로 개발하던 C++ 프로그램을 불가피한 사정 때문에 더 낮은 버전인 Visual C++ 2012로 빌드할 일이 있었다.
빌드는 별 문제 없이 됐지만, 그 프로그램은 제대로 실행되지 않고 초반부에서 바로 뻗어 버렸다.

디버거로 들여다보니 원인이야 어처구니 없는 실수 때문이었고 금방 밝혀졌다. 클래스의 생성자에서 멤버들이 ABC~XYZ 순으로 초기화되는데, A~C의 초기화 과정에서 아직 초기화되지 않은 뒤쪽 멤버들을 참조하는 멤버 함수를 호출했던 것이다.
컴파일러가 지역 변수 int를 초기화하지 않고 사용하는 것 정도는 곧장 지적해 주지만, 저런 실수까지 찾아내는 건 정적 분석의 경지로 가야 하는 모양이다.

그런데 문제는 이런 버그가 오랫동안 존재했던 프로그램이 지금까지 2015로 빌드할 때는 왜 잘만 돌아갔느냐는 것이다. 그것도 디버그가 아닌 릴리즈 빌드로 말이다. 이 객체는 new로 heap에다가 할당하는 것이어서 전역변수와는 달리 초기에 내부 메모리가 언제나 0초기화라는 보장도 없는데..
더구나 C++은 성능 덕후 언어이기 때문에 파생 클래스 부분까지 기본적인 초기화를 다 해 준 뒤에 기반 클래스의 생성자를 호출하는 것도 아니고, 생성자에서 자신의 초기화되지 않은 부분을 건드려서 순수 가상 함수 호출 같은 각종 문제가 얼마든지 발생할 수 있는데... 언어 디자인이라는 구조적인 차원에서 말이다.

프로그램의 빌드 configuration을 바꾸면 한 환경에서는 없던 문제가 금세 튀어나올 수 있다. 디버그에서 릴리즈, 혹은 반대로 릴리즈에서 디버그로 양방향이 모두 가능하다.
또한, 평소에는 탄탄한 최신 NT 계열 Windows에서 개발하다가 프로그램을 더 불안하고 연약한 환경인 9x에서 돌리면 숨겨진 버그나 리소스 누수가 튀어나올 수 있다. 요즘 컴파일러에서는 이렇게 할 수조차 없지만 말이다.

그런데 컴파일러의 버전을 더 낮췄더니 숨겨진 문제가 튀어나온 경험은 이번이 거의 처음이었다.

Posted by 사무엘

2017/11/29 08:32 2017/11/29 08:32
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1432

Trackback URL : http://moogi.new21.org/tc/trackback/1432

Leave a comment

1. 수동 변속기

자동차 운전을 오래 한 나이 지긋하신 분들은.. 전자 기기 일색이 된 요즘 차에서는 경험할 수 없는 옛날 차량의 '단순무식하고 견고한 특성'에 대해 일종의 향수를 갖고 있는 편이다.

대표적인 예 중 하나는 단연 수동 변속기이다. 수동은 엔진의 힘이 고정된 비율로 곧이곧대로 바퀴에 전해지며, 강한 힘이 필요할 때도 저단에서 밟으면 밟는 대로 곧장 나간다.
그에 반해, 자동은 가속 페달을 깊게 꾹 밟은 채로 1초 남짓 좀 기다려야 킥다운이 일어나면서 추진력이 올라간다. 특정 단이라는 개념이 없고 시동 꺼뜨리는 일도, 클러치 일일이 밟고 떼는 불편도 없는 대신, 차가 운전자의 의중을 '간보고' 보정하기 위해 어느 정도 딜레이가 필요하다.

이건 수동 운전의 사고방식으로는 상상도 할 수 없는 일이다. 불편하게 일일이 클러치 밟고 떼도 좋으니, 차의 모든 상태를 자기가 스스로 파악하고 통제하고 결정하기를 원하는 골수 기계덕이라면, 자동보다 수동을 모는 게 마음이 더 편할지도 모르겠다.
그러나 그런 사람들도 수동 운전을 좋아하는 것과는 별개로, 오르막에서 멈췄다가 뒤로 안 밀리고(특히 뒷차와 부딪치지 않고) 매끄럽게 출발하는 건 어려워하고 부담스러워하는 경우가 많다고 한다.;;

자동 변속기의 등장 초창기에는 킥다운조차도 버튼이 따로 있어서 이걸 사용자가 수동으로 알려 줘야 하기도 했다.
오늘날도 자동이라고 해서 언제나 D에만 갖다놓고 때때로 킥다운만 하는 게 장땡은 아니다. 저단 고정이라든가 오버드라이브, 파워 모드 같은 미세한 제어 옵션이 달려 있다. 오르막· 내리막, 추월 같은 상황에서 이를 적절히 활용하면 주행 연비를 개선할 수 있다.
(오버드라이브는 끌 경우 3 또는 4단 이하 변속만 허용하는 그냥 또 다른 형태의 저단 고정 기능 아닌가? 그런데 옛날엔 왜 따로 특별히 소개했는지 이유를 잘 모르겠다.)

참고로, 파워 모드는 단순히 자동 변속 조건을 평소보다 더 높은 rpm 시점으로 바꾸는 역할을 한다. 말 그대로 변속기의 수준에서 연비를 좀 희생해서 속도보다 가속력을 중시하는 결정을 내릴 뿐, 다른 마법을 동원해서 엔진에 힘을 더 불어넣는 건 아니다.

2. 카뷰레터

지금까지는 변속기 얘기를 했다. 그런데 옛날에는 자동차에 동력비의 변환만 수동· 기계식인 게 아니라 연료 분사까지 아주 원시적인 수동· 기계식이던 시절이 있었다.

운전자가 가속 페달을 밟으면 차에 힘을 내기 위해서 연료고 공기고 뭐든지 많이 공급해 줘야 하는데, 이거 비율을 적절하게 맞추는 게 생각보다 어려운 일이었다. 그게 적절하지 않으면 기껏 많이 공급한 연료가 제대로 연소하지 못해서 힘은 힘대로 안 나면서 연비는 안드로메다로 가고, 배기가스만 잔뜩 나올 수 있었다. 디젤의 경우는 이건 더 심각한 문제이다.

전동차로 치면 저항 제어만큼이나 가장 원시적인 연료 공급 메커니즘은 기화기라고도 불리는 카뷰레터 방식이다. 이건 아주 간단히만 설명하면, 전자 기기가 정밀하게 뭔가를 통제하는 것 없이, 공기의 흐름을 따라 물리 법칙에 의해서 연료가 저절로 기화되어 섞이고 혼합 기체가 되게 한 것이다.

이런 카뷰레터 방식의 자동차는 단순 무식하게 밟으면 밟는 대로 엔진 rpm이 막 올라가고 반응성이 좋았다고 한다. 이건 안 그래도 수동 변속기의 장점이기도 한 특성인데.. 옛날 카뷰레터 엔진 차량의 엔진룸을 열어 보면 둥근 밥통처럼 생긴 헤드가 달려 있었다.

사용자 삽입 이미지

하지만 원시적인 카뷰레터의 단점은 아까도 말했듯이 연비와 환경 문제이다. 그런 단순무식한 방법으로 연료를 공급해서는 요즘 자동차 같은 효율을 절대로 달성할 수 없다.

또한, 굳이 가속을 안 하더라도 엔진이 돌면 도는 만큼 연료가 자연적으로 소모되는 매우 큰 문제가 있었다고 한다. 즉, 퓨얼컷(fuel cut)이라는 게 없었다. 내리막에서 저단 엔진 브레이크를 걸어서 전적으로 바퀴를 따라 엔진 회전수가 올라간 건데도 연료는 그 회전수에 맞춰서 쿵짝쿵짝 소모되었다.

그렇기 때문에 옛날에는 긴 내리막을 갈 때는 시동을 끄는 것까지는 위험하지만 기어를 차라리 중립으로 맞춰서 rpm을 줄이는 게 연비에 좋다는 팁이 통용될 정도였다. 지금으로서는 상상도 할 수 없는 모습이다.

그 시절 옛날 자동차들은 주변 기온에도 더 민감했다. 날씨가 너무 추우면 배터리 같은 전기 장치뿐만 아니라 엔진도 잘 안 돌았다. 그래서 시동을 건 뒤에 어느 정도 공회전 예열이 필요했고, 또 시동이 잘 안 걸릴 경우 '초크 밸브'라는 걸 당겨서 연소실에 공기를 강제로 더 불어넣거나, 반대로 줄여서 연료의 농도를 올려 줘야 했다. 같은 힘을 내는 적정 공기량은 온도에 따라 달라지는 편인데 그걸 기계식 카뷰레터만으로는 알맞은 값을 스스로 감지할 수 없었기 때문이다.

그에 반해 요즘 자동차들이야 ECU 기반의 전자식 인젝터에, 간접 분사도 넘어서 직분사 같은 다양한 연료 분사 기술이 개발되었고 저런 번거로운 절차들은 다 자동화되었다. 공회전은 쓸데없이 오래 할 필요가 전혀 없으며, 내리막길을 갈 때는 엔진 브레이크 잘만 쓰면 된다. 오히려 중립은 시동 유지를 위해서 공회전만치의 연료가 들지만, 바퀴에 의해 엔진이 저절로 돌아가고 있을 때는 연료가 진짜로 전혀 들지 않는 퓨얼컷이 실현된다.
즉, 약간의 단순무식 거칠고 날렵함을 희생한 대신, 요즘 자동차는 더 똑똑해지고 운전하기 편해지고 성능과 경제성, 친환경성이 더 강화된 셈이다.

비행기만 해도 주변 온도와 공기 밀도, 기체의 중량 같은 온갖 복잡한 변수를 고려해서 V1 속도와 활주거리가 결정되는데, 자동차도 비록 그 정도까지는 아닐지라도 엔진 시동과 구동은 매우 섬세하고 복잡한 변수가 많은 메커니즘인 것 같다.
이런 옛날 자동차와 요즘 자동차의 특성을 감안했을 때, 고연비 고효율, 차에 좋은 주행을 하는 요령을 몇 가지 나열하면 다음과 같다.

1. 시동 건 직후에 워밍업 공회전 쓸데없이 오래 하지 말 것.

물론 엔진 오일의 점성과 냉각수 온도를 맞추기 위해 길어야 10~20초 정도.. 시동 직후의 엔진 rpm이 좀 낮아질 때까지는 기다리는 게 좋다. 하지만 혹한에서 디젤 차량 정도가 아닌 이상, 분 단위의 공회전은 전혀 필요하지 않다.
긴 공회전과 예열은 바로 저 옛날 카뷰레터(기화기) 엔진 시절의 잔재일 뿐이다.

2. 내리막이나 평지에서 기름 아끼고 싶다고 쓸데없이 N으로 바꾸지 말 것.

요즘 차들은 똑똑하기 때문에 차라리 D를 유지하고 상황에 따라 다음 둘 중 한 테크닉의 혜택을 입는 게 훨씬 더 낫다.

(1) 액셀 페달을 아예 안 밟아서 엔진 브레이크 + 퓨얼컷: 비록 완전 중립 관성 주행일 때보다는 차의 속도 감소 폭이 더 크지만, 이때는 전적으로 바퀴 관성만으로 엔진이 돌아가면서 연료가 아예 소비되지 않는다(이미 1500rpm 이상 정도로 엔진이 돌고 있는 경우). 그 반면, 중립일 때는 아이들링 rpm 유지를 위해서 기본적인 연료는 소모됨.
긴 커브+내리막에서 저단 엔진 브레이크는 브레이크 페달의 부담도 어느 정도 덜어 주는 굉장히 좋은 테크닉이다. 시속 100km 상태에서 1단.. 같은 미친 짓만 안 하면 된다.

(2) 액셀 페달을 얇게 꾸준히 밟아서 락업 클러치: 이러면 엔진 힘이 변속기의 토크 컨버터를 안 거치고 바퀴로 바로 전해진다. 특히 시속 60~80km급의 경제 속도에서 주기적인 재가속 없이 반쯤 크루즈 상태로 주행하면 가히 최강 연비를 달성할 수 있다.

3. 신호 대기처럼 작정하고 오래 정차가 예상된다면, D+브레이크 꿋꿋이 유지하는 것보다는 N으로 바꾸는 게 좋음.

요즘 차들은 D+브레이크 정차 상태가 오래 계속되면 자동 중립으로 최적화도 해 준다고는 한다만.. 일단은 기계적으로 봤을 때, 가려는 차를 억지로 붙잡고 세워서 변속기를 열받게 하는 것보다는, 직접 엔진과 바퀴를 분리시켜서 불필요한 동력을 끊어 주는 게 더 낫다. 똑같이 정차 공회전을 해도 N일 때 연료 소모가 약간이나마 더 적었다는 실험 결과도 있다. 수동에서 저랬으면 차가 견디지 못하고 바로 시동이 꺼졌을 것이다.

2와 3을 한데 요약하면, 변속기의 본래 설계 취지에 맞게 D는 주행할 때만 쓰고, N은 정차할 때만 쓰면 된다.
컴퓨터에서도 과거에 통했던 성능 최적화 꼼수들이 멀티코어 병렬화 시대가 되면서 통하지 않게 된 게 많은데 뭐 그런 걸 보는 느낌이다.

4. 주차하느라 전진· 후진을 자주 전환할 때.. 차가 완전히 서기 전에 P 또는 반대 진행 방향 기어로 절대 절대 성급하게 바꾸지 말 것.

이건 옛날 차든 요즘 차든 공통으로.. 모든 자동차 전문가들이 이구동성으로 말하는 당부사항이다.
엔진 브레이크야 변속기가 브레이크의 역할을 일부 도와주는 것이다. 하지만 엔진 브레이크는 애초에 아이들링 rpm의 크리핑 속도보다도 더 느리게 차를 완전하게 세우는 기법이 전혀 아니다. 아이들링 rpm 상태에서도 차가 내는 힘은 엄청나며, 브레이크의 제동력으로 감당해야 할 힘을 변속기가 받으면 변속기가 망가진다. "시속 100km에서의 1단"과는 반대 방향 극단으로 차가 무리를 받게 된다.

잦은 변속 자체는 변속기를 닳게 하거나 차의 수명을 떨어뜨리는 짓이 결코 아니다. 단지, 차가 완전히 서지 않았을 때 변속하는 것이 변속기에 무리를 줄 뿐이다. 위의 성질 급한 관행으로 인해 차가 고장 나는 것 때문에 정차 중에 정상적으로 N에다 두는 것까지도 차에 안 좋은 것처럼 오해받는 것이다.
그 밖에, 빨리 튀어나가려고 정지 상태에서 미리 rpm 왱알앵알 거리거나, 구동축 바퀴를 헛돌게 하는 것도 웬만하면 하지 말 것..;

Posted by 사무엘

2017/11/26 08:33 2017/11/26 08:33
, , ,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1431

Trackback URL : http://moogi.new21.org/tc/trackback/1431

Leave a comment

하루는 식당에서 저녁을 먹는데, 저 멀리 텔레비전에서는 무슨 쇼 프로에서 연예인들이 등산을 하는 장면이 나왔다. 주변이 시끌벅적하고 화면이 잘 안 보였지만, 그래도 저 고깔 모양의 정상 표지석은 99% 청계산 매봉이라는 확신이 들었다. TV 근처로 다가가서 확인해 보니 내 예상이 맞았다.

예전에는 깜깜한 밤에 지상 전철 승강장에서 저 멀리 보이는 헤드라이트 불빛의 모양만 보고는 8000호대 전기 기관차가 오는 거라고 예상을 했고 예상이 실제로 적중한 적이 있었다. 뭐, 이것도 철덕에게는 기본 중의 기본 스킬이겠지만.. 철도만큼이나 등산도 짬이 차니까 이런 감까지 생기는구나 싶었다.

서울 강북에 북한산· 도봉산· 수락산 같은 산이 있다면 강남에는 관악산과 청계산이라는 제법 크고 높은 네임드급 산이 있다. 청계산은 전반적으로 흙산이기 때문에 손으로 로프를 잡고 올라야 하는 건 거의 없으며, 오르기 쉬운 편에 든다.
신분당선이 개통한 뒤에는 '청계산입구'라는 역이 생긴 덕분에, 거기 근처에 있는 서울 신원동 등산로로는 주말에 등산객이 굉장히 늘었다. 기슭에는 산악용품 가게와 등산객 뒤풀이용 식당들이 즐비하다. 신분당선이 없던 시절에는 4432 같은 버스가 청계산으로 가는 길을 책임졌던 것으로 본인은 기억한다.

거기서 옥녀봉 또는 582m짜리 매봉 정상까지 갔다가 그대로 돌아오는 게 무난한 코스이다. 내 기억으로 매봉 정상은 미묘하게 갈림길도 있다. 입산과 하산 지점은 동일하지만 중간에 거치는 경로를 달리할 수 있다. 본인은 그쪽으로 청계산 등산은 회사 사람과도 하고 교회 사람과도 해 봤다.

하지만 거기보다 더 남쪽으로 서울을 벗어난 성남시 고등동· 상적동 옛골 마을 일대에도 청계산 등산로가 있다. 4432의 종점 근처인데, 본인은 옛날에 인릉산을 찾아갈 때 여기까지 가 본 적이 있다. 그 시절엔 거기에서 또 청계산을 오를 생각은 미처 못 했으며, 예전에 갔던 매봉이 청계산에서 가장 높은 정상이기 때문에 청계산을 더 오를 필요는 없다고 생각했다.

그런데 알고 보니 청계산에는 매봉보다 더 높은 정상이 존재할 뿐만 아니라 거기에는 우면산이나 성남 검단산처럼 공군 방공 부대도 있다. 민간인 등산객은 거기로 접근할 수 없고 거기서 살짝 떨어진 곳의 공터를 정상인 줄 알고 간다.
이렇게 흥미로운 정보들이 많이 입수되었기 때문에 본인은 지금까지 들른 적이 없는 청계산 등산로와 정상을 개척하기 위해 성남시 상적동 옛골 마을을 찾아갔다.

사용자 삽입 이미지사용자 삽입 이미지

옛골 마을은 이렇게 생긴 평온한 동네이다. '상적천'이라는 개천이 지나며, 이 때문에 근처의 경부 고속도로도 여기는 살짝 교량 형태로 지난다(상적교). 주변엔 등산객을 위한 식당과 카페가 많지만 막 유명한 유원지 같은 정도는 아니다.
저기까지 대중교통으로 갈지 아니면 아예 차를 가져갈지 고민하다가 차를 선택했다. 딱 봐도 아무 곳에나 딱히 주차 걱정을 할 필요는 없어 보이는 곳이며, 이번에는 등산 경로를 여기로 다시 돌아오는 형태로 계획했기 때문이다.

안 그래도 등산을 마친 뒤에 몸이 땀범벅 녹초가 됐는데, 편안한 귀가를 위해 차를 가져간 건 아주 잘한 선택이었다. 새벽에 적당한 곳에다 차를 세워 놓은 뒤, 차에서 한숨 자고 나서 아침부터 산을 오르기 시작했다.

사용자 삽입 이미지

마을 어귀에는 이렇게 청계산 꼭대기의 군부대로 가는 길이 떡 놓여 있었다. "경고 - 민간인 차량 통제"라는 팻말과 함께 말이다.
사실은 경부 고속도로 부산 방면에서도 이 길로 합류하는 비밀 진출로가 있다. 마치 헌릉로에서 국정원으로 들어가는 진출로처럼 말이다. 경부 고속도로 개통 초기에는 "상적 IC"라고 진출입로가 정식 등재도 돼 있었지만 나중에 슬그머니 폐쇄된 듯하다. 비상 활주로만큼이나 고속도로의 또 다른 군사 활용의 예라 하겠다.

하지만 민간인은 차량만 못 들어갈 뿐이지, 보행자 등산객은 저기로 통행 가능하다. 저기에는 엄연히 성남 누비길 구간과 청계산 등산로가 포함되어 있기 때문이다.

사용자 삽입 이미지

이런 길을 따라 오르막을 오르면 군부대 초소가 나온다. 민간인은 초소 너머 군부대 내부로는 물론 들어갈 수 없지만, 그래도 차도를 벗어나 옆으로 등산로로 들어갈 수 있다. 본인의 등산은 이렇게 시작되었다.

사용자 삽입 이미지

옻샘 약수터에 도달했다. 맑고 시원한 물 보급을 받을 수 있어서 무척 좋았다.
북쪽의 매봉이 아니라 남쪽의 망경대 방면으로 가야 하는데, 마침 옻샘이 나왔다는 건 지도상으로 계획했던 길을 잘 찾아간 것이었다.

사용자 삽입 이미지사용자 삽입 이미지

산길은.. 숲이 울창하고 뭐 이런 분위기였다. 날씨가 무척 맑고 좋았다.

사용자 삽입 이미지

처녀 폭포라는 자그마한 폭포가 있어서 들렀다.
그리고 여기 부근(대략 4~500 m 떨어진..)에는 군부대로 향하는 샛길도 있었다. 본인 역시 따라 가서 주변 구경을 좀 하다가 되돌아왔다.

사용자 삽입 이미지

중간에 '힐링의 숲'이라고, 그냥 평범한 탁자나 벤치, 마룻바닥뿐만 아니라 저렇게 S자형으로 반쯤 누울 수 있는 목재 의자가 산에 놓여 있었다. 저기 누워 있으니까 굉장히 편하긴 했다. 이대로 한숨 자고 싶을 정도였다.

사용자 삽입 이미지

힐링의 숲 이후부터는 이정표 없이 한참 동안 가파른 오르막을 올라야 했다.
그러다 드디어 '혈읍재'라고 불리는 고개에 도달했다. 고개의 이름이 '피가 울다'라는 섬뜩한 뜻인 이유는 조선 시대와 관련된 역사적 사연이 있다.
거기에서부터 또 계단을 타고 한참을 오르면 이제 정상이 얼마 안 남았는지 옆으로 철조망을 따라 군사 시설이 보이고... 나중에는 이런 넓은 공터가 나타났다.

위의 사진 시야를 기준으로 전방에 있는 작은 길은 산을 내려가는 찻길이다. 저 길 자체는 민간인도 통행 가능해 보였지만, 본인은 아직 하산할 생각이 없으므로 저기로 가지 않았다.
사진에 나오지 않은 뒤로는 각종 차들이 세워져 있었다. 번호판이 '국'인 희귀한 차량도 있었다(국방부 소속!!).

그리고 역시 사진에 나오지는 않았지만 오른쪽으로, 위쪽의 건물 방면으로 올라가는 찻길이 있었다. 망경대 정상으로 간 뒤 이수봉 방면으로 산행을 계속하려면 그 오르막길을 가야 했다. 본인은 그 방향을 선택했다.

사용자 삽입 이미지

저 멀리 우측 상단의 관악산 정상이 보인다. 산 아래에 있는 건물들은 과천 시내이다.
청계산은 전반적으로 나무로 빽빽하게 덮여 있으며, 등산 중에 산 아래를 내려다볼 만한 전망대 같은 곳은 거의 전무하다. 그나마 정상에 근접해서야 이런 사진을 찍을 만한 곳이 나왔다. 그리고 위의 사진은 아직 완전히 정상에 도착해서 찍은 건 아니다.

사용자 삽입 이미지

청계산 봉우리들의 다른 정상들은 다 흙바닥 공터이고 정상 표지석도 있는 반면, 망경대만은 북한산이나 도봉산의 정상처럼 꼭대기가 그냥 바위였다. 청계산에서 유일하게 밧줄 붙잡고 꽤 아슬아슬하게 올라야 했다. 여기는 본인도 부득이하게 백팩을 아래에다 내려다놓고 몸만 올라갔다. 위의 사진에서 본인 손에 맥북이 들려 있지 않은 게 이 때문이다.

주위를 둘러보니 덜 위험한 우회 등산로를 거쳐서 바위로 오는 길도 있어 보였다. 하지만 놔 두고 온 백팩 때문에 그리로 내려가 볼 수도 없었다.
이 정상은 곁에 있는 군부대가 자리잡은 봉우리보다는 약간 미묘하게 낮지만, 그래도 아까 그 흰 돔이 2개 달린 관측 시설보다는 훨씬 높았다. 국가 안보를 위해 이 시설들을 찍은 사진은 블로그에 게재하지는 않기로 하겠다. 궁금하신 분은 직접 등산 가서 보시길..

사용자 삽입 이미지

서울랜드가 내려다보였다. 저기는 한때는 잘나갔었으나.. 시설물의 퀄리티가 넘사벽급 대기업 관할인 롯데월드와 에버랜드에 비할 바는 못 되니 슬슬 인기가 하락하는 중이다.

사용자 삽입 이미지

서울 공항 방면으로도.. 본인은 저 앞에 보이는 산들도 나름 올라 봤다. 저 멀리 병풍 같은 산이 바로 성남과 광주의 경계 역할을 하니까 말이다.

사용자 삽입 이미지

망경대 바위 위에서 경치 구경을 실컷 한 뒤, 본인은 하산하여 남쪽으로 계속 걸어갔다. 내려가던 중에 이렇게 평평하고 나무가 없는 공터가 나왔다.
위의 사진은 저 흰 돔이 보이는 것에서 알 수 있듯, 뒤 돌아서 왔던 길 쪽으로 찍은 것이다. 이 공터에서는 아래로 내려가는 찻길 또는 이수봉 방면 오르막 도보 등산로를 선택할 수 있었다. 본인은 이수봉 쪽으로 갔다. 여기를 끝으로 찻길 분기점은 더 등장하지 않았다.

사용자 삽입 이미지

그래도 중간에 이런 헬리패드가 나왔으며..

사용자 삽입 이미지

한참을 산을 더 오른 뒤에야 드디어 이수봉에 도달했다. 본인은 지금까지 청계산에서 이런 정상 표지석을 본 적이 없으니, 새로운 등산로 탐험을 이 기회에 그럭저럭 잘 해냈다.
이제 하산을 시작했다. 하산도 길 잃지 않고 잘 해서 차가 있는 곳으로 무사히 돌아가야 하니까 말이다. 이정표가 나오면 국사봉이나 과천 매봉 방면 말고 '옛골'이라고 적혀 있는 곳만 골랐다.

사용자 삽입 이미지

하산을 시작한 지 얼마 안 되어 철조망이 쳐진 거대한 구역이 나타났다. 그런데 평범한 '군사 시설, 무단 접근과 촬영을 금함 -- oooo부대장'이 아니라, 관리 주체가 웬 듣도 보도 못한 기관인 '도시환경 연구소'라고 적혀 있었다. 본인으로서는 인터넷 검색을 해 봐도 정체를 알 길이 없다.
철조망 사진도 이곳에다가 대놓고 올리지는 않겠다. 위의 사진은 철조망 구역을 다 지나치고 나서 다시 울창한 숲이 등장한 뒤의 하산 경로 풍경을 찍은 것이다.

사용자 삽입 이미지

한참을 내려가다 보니 언제부턴가 물이 졸졸 흐르는 계곡이 길 옆에 등장했다. 이 계곡이 아래의 상적천으로까지 이어지는 모양이다. 그리고 올라갈 때 옻샘 약수터를 만났다면, 내려올 때는 '천수샘 약수터'를 지났다. 하지만 여기 물은 대장균이 기준치 이상으로 검출되어 음용 불가라고 옆에 쓰여 있었다.

산을 오를 때는 종아리가 힘들고 땀이 왕창 나고 물도 많이 마시게 되는데, 내려갈 때는 그런 식으로 덥고 힘든 것은 없다. 그 대신 무릎과 발목 관절이 남아나질 못하는 것 같았다. 등산을 오랜만에 해서 그런지 슬슬 삭신이 쑤시고 다리가 후들거리기 시작했다.

사용자 삽입 이미지

착륙이 이제 얼마 안 남았다. 등산로 옆으로 갑자기 이런 밭이 등장했다. 그리고 저 고개 너머엔 사격장이 있는지 본인이 방문하던 당시에 사격 훈련을 하고 있었다. 총소리가 막 들렸다. 실제로 구글 어쓰로 보니 그쪽엔 예상대로 사격장처럼 생긴 시설이 보였다.

사용자 삽입 이미지

아까 그 밭에서 거의 6, 700미터쯤 걸은 뒤에야 옛골 마을이 다시 등장했으며, 본인은 모든 등산과 하산을 계획했던 경로로 잘 마쳤다.
정리하자면, 청계산 정상까지 올라가는 차도는 앞부분은 기슭의 군부대 때문에 막혀 있지만, 정상 인근의 군부대가 다시 등장할 때까지 그 사이 구간은 등산객도 이용할 수 있는 것 같다.

서울 시내 구간만 이용할 때는 청계산에 군부대가 있다는 생각은 별로 안 들었는데(단지, 1982년의 C-123 수송기 추락 사고로 순직한 특전사 장병에 대한 위령비만 있을 뿐), 이렇게 남쪽의 그린벨트 지대를 차로 답사하고 군사 시설 위주로 청계산의 진짜 정상도 구경하고, 계곡도 구경하는 등 굉장히 큰 성과를 올렸다. 즐거운 시간이었다.

Posted by 사무엘

2017/11/23 08:31 2017/11/23 08:31
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1430

Trackback URL : http://moogi.new21.org/tc/trackback/1430

Leave a comment

1. 주 UI 스레드와 배경 작업 스레드

대화상자를 텅 빈 깡통 상태로 일단 띄워 놓은 뒤, 시간이 좀 오래 걸릴 수 있는 초기화 작업을 백그라운드에서 하고서 그게 끝나면 작업 결과를 대화상자의 각종 컨트롤에다가 반영하고 표시하기..
본인은 이런 형태로 동작하는 GUI를 구현한 적이 있었다. 리스트/콤보 박스에 들어갈 아이템들을 파일을 탐색하면서 수집하는 것이 대표적인 예이며, 당장 날개셋 한글 입력기 프로그램에도 이렇게 동작하는 UI가 한두 군데 있다.

그런데 그 백그라운드 작업이 언제나 수행되는 건 아니고, 조건에 따라서는 전혀 해당사항이 없는 경우도 있었다. 이때는 작업 결과의 표시와 관계가 있는 컨트롤들은 그냥 숨기거나 disable 시켜 놓으면 됐다.

그러니, 그런 컨트롤은 괜히 만들었다가 도로 숨기는 게 아니라, 스레드 함수가 자기 작업이 다 끝나고 마지막 부분에서 대화상자에다가 동적으로 생성하게 로직을 고치는 게 어떨까 생각을 했는데... 그렇게 하다가 더 피봤다.
당연한 말이지만 특정 스레드가 생성한 윈도우는 그 스레드의 실행이 끝남과 동시에 소멸되기 때문이다. 머리에 나사가 하나 빠지기라도 했는지 왜 그걸 생각을 못 했나 순간 "아차~!" 했다.

컨트롤 자체는 주 UI 스레드에서 미리 만들어 놓은 뒤, 백그라운드 작업 스레드에서는 그걸 ShowWindow / EnableWindow 정도의 제어만 할 수 있다. 컨트롤을 굳이 조건부로 동적 생성하고 싶다면, 백그라운드에서는 주 UI로 하여금 컨트롤을 생성하라고 메시지나 타이머 요청 정도를 보내는 간접적인 방법만 사용 가능할 것이다.

이렇게 윈도우의 생명 주기는 스레드와 관계 있는 반면, 접근 가능한 윈도우 클래스의 범위는 드물게 스레드가 아니라 RegisterClass를 호출한 모듈과 관계가 있다. 한 프로세스 안의 모든 모듈에서 접근 가능한 윈도우 클래스를 구현하려면 클래스 스타일에 CS_GLOBALCLASS를 지정해 줘야 한다. CreateWindowEx 함수는 현 스레드의 함수 호출 스택을 추적해서 자신을 호출한 모듈이 무엇인지를 따지기라도 하는가 보다. (인자로 받은 HINSTANCE 값은 무시하고 사용하지 않음.)

Windows 말고 안드로이드 프로그래밍을 해 보니 거기서는(Java)는 네트워크 통신은 무조건 백그라운드 스레드에서만 가능하고, 각종 GUI 요소의 조작은 반대로 주 스레드에서만 가능하게 해 놓았다. 이 규칙을 어기면 바로 예외가 발생한다. 그래서 Windows에서와 같은 혼동이 발생할 일이 없게 해 놨지만.. 간단한 통신 결과가 왔을 때 이를 GUI에다 표시하는 걸 한 함수에서 바로 못 하고 매번 스레드에, 메시지+핸들러로 실행 주체를 분리해야 하는 게 좀 번거로웠다.

2. 스레드의 강제 종료와 스택 상태

프로세스가 종료되는 가장 무난하고 좋은 방법은 main / WinMain 함수가 실행이 끝나서 자연스럽게 return하는 것이다. 그와 마찬가지로 스레드가 종료되는 가장 무난하고 좋은 방법 역시 해당 스레드 함수가 실행이 끝나서 자연스럽게 return하는 것이다.
하지만 Windows API에는 Exit...내지 Terminate...로 시작하는 프로세스· 스레드 종료 함수가 따로 있다.

두 단어 모두 뜻은 비슷하나, 전자는 자동사이고 후자는 목적어를 받는 타동사이다. 이로부터 유추할 수 있듯, 전자는 그 함수를 호출하는 자신을 종료하고 후자는 임의의 다른 프로세스나 스레드를 강제 종료시킨다.
어떤 프로세스가 이런 함수에 의해 종료되면 그 프로세스 하에서 돌아가던 모든 스레드들은 강제 셧다운된다. 그리고 반대로, 어떤 프로세스에서 모든 스레드들이 종료되어서 돌아가는 스레드가 하나도 없는 지경이 되면 빈 껍데기 프로세스는 자동 종료되고 소멸된다.

main 함수의 실행만 끝나면 자동으로 주변 잔여 스레드들의 실행도 강제로 다 끝나는 것 같지만 원래부터 그렇지는 않다. main을 호출한 하단의 C 런타임 라이브러리가 내부적으로 ExitProcess를 호출하기 때문에 그렇게 되는 것일 뿐이다. 운영체제 차원에서는 모든 스레드들의 실행이 끝나야 프로세스가 종료된다.

어쨌든, 프로세스나 스레드 같은 실행 주체는 자기 스스로 곱게 종료하는 게 좋다. 강제 종료 대상인 프로세스나 스레드는 자신이 강제 종료 당한다는 어떤 통지도 받지 못하며 이를 회피· 거부할 수도 없다. 뭐, 강제 종료를 막는 방법 뒷구멍이 있다면 악성 코드가 이를 마음껏 오· 남용, 악용할 것이니 저건 불가피한 면모도 있다. 강제 종료를 요청하는 프로세스가 적절한 권한만 갖고 있다면 강제 종료 작업 자체는 성공이 반드시 보장된다.

강제 종료는 파일이나 메모리, 스레드 동기화 오브젝트를 포함해 해당 스레드가 할당하고 선점해 놓은 그 어떤 자원도 제대로 수습· 회수하지 않은 채 말 그대로 해당 실행 주제만 없앤다. 그러니 엄청난 리소스 누수를 야기한다. 그나마 프로세스는 독립성이 높은 실행 단위인 덕분에 강제 종료되더라도 자기가 사용하던 모든 자원들이 자동으로 반납되는 게 보장이라도 되는 반면, 스레드는 그렇지 않다.

그렇기 때문에 TerminateThread는 TerminateProcess보다도 가능한 한 더욱 사용하지 말아야 한다.
I/O 관련 병목이나 데드락 같은 게 걸려서 해당 스레드의 코드 자체가 전혀 돌아가지 않을 때.. 옛날 같았으면 컴퓨터 리셋을 했을 피치 못할 상황에서나 극도로 제한적으로 사용해야 한다. 자기 스스로 실행 가능한 스레드라면 외부에서는 중단· 종료 플래그만 걸어 주고, 그 스레드가 알아서 실행이 종료되게 하는 것이 절대적으로 바람직하다.

그렇기 때문에 작업 관리자 같은 유틸에서 응용 프로그램을 강제 종료하는 기능은 일단 그 프로그램의 주 윈도우에다 WM_CLOSE만 살짝 보내 보고, 그 프로그램이 거기에 불응하면 API 차원의 극약 처분을 내리는 식으로 동작한다. 기왕이면 주먹보다는 말로 곱게 해결하는 게 좋으니까...

스레드가 강제 종료된 경우, 코드 실행 차원에서 발생하는 리소스 leak이야 어쩔 수 없는 귀결이다. 그런데 Windows는 전통적으로 exit 말고 terminate로 강제 종료된 스레드에 대해서는 그 스레드가 사용하던 스택에 속하는 메모리 주소도 해제· 재사용하지 않고 내버려 뒀다. 그러니 heap이 아닌 stack에 속하는 메모리가 leak이 발생하게 됐다.

이것은 스레드가 강제 종료되더라도 그 스레드의 스택에 속하는 메모리를 참조하던 다른 스레드가 뻗지 않게 하려고 성능보다는 안전을 고려해서 시행한 정책이었다. 어차피 TerminateThread를 할 정도이면 온갖 리소스들이 누출되었을 가능성이 높고 이왕 버린 몸에 비정상적인 상황이니 스택도 해제하지 않고 일부러 놔뒀던가 보다.
그러나 이 정책이 Windows Vista부터는 바뀌어서 이제는 terminate된 스레드의 스택도 곧장 해제된다. 흥미로운 점이다.

3. 열악하던 시절에 동시작업 구현하기

CPU 차원에서의 멀티스레드라는 게 없던 시절에 UI와 백그라운드 작업이 동시에 돌아가는 프로그램을 짜는 건 상당한 고역이었다.
옛날에는 컴퓨터 하드웨어 차원에서 관리되는 키보드 버퍼라는 게 있었다. 컴퓨터가 바빠서(busy) 정신없는 상태에서 사람이 키보드를 누르면 그게 일단 버퍼에 들어갔으며, 나중에 컴퓨터가 정신을 차리면 먼저 온 글쇠부터 밀린 처리를 했다. 일종의 queue 자료구조처럼 말이다.

이 키보드 버퍼는 크기가 15타 남짓밖에 안 됐다. 그러니 컴퓨터가 바쁜 상태에서 키보드를 조금만 많이 누르면 그 글쇠는 버퍼에조차 추가가 못 되고 컴퓨터가 시스템 전체를 잠시 멈추면서 높은 톤의 '삐~' 경고음을 냈다. "나 건드리지 마세요..!" 물론 ctrl, shift 같은 비문자 글쇠 말고 문자 글쇠들 한정으로. pause 키를 누르면 컴퓨터 전체의 실행을 일시정지 시킬 수 있던 시절의 얘기이다.

Windows 시대가 되면서 하드웨어와 소프트웨어 사이에 무슨 계층이 덧붙여졌는지, 컴퓨터에서 저런 걸 볼 일은 없어졌다. 하지만 9x 시절에는 운영체제가 대미지를 심하게 입고 반쯤 뻗어서 다운+재부팅 징조가 농후할 때면, 윈도우들이 메시지 큐가 다 차 버리고 메시지에 아무런 응답도 처리도 할 수 없는 상태가 되곤 했다. 이때는 그 윈도우로 마우스 포인터를 갖다대서 옮기기만 해도 짤막한 비프음이 났다. 이게 옛날에 키보드 버퍼가 다 차서 경고음이 나던 것과 같은 맥락의 현상이다.

옛날에 컴퓨터 속도가 왕창 느릴 때는 사용자가 화살표 키를 눌러서 화면을 스크롤 하던 도중에도 끊임없이 글쇠 입력 체크를 해야 했다. 그래서 화면 갱신 속도가 글쇠 연타 속도를 따라가지 못한다면 지금 갱신하던 것은 때려치우고 글쇠 처리부터 모두 한 뒤, 이로 인해 화면 위치가 바뀌었으면 스크롤을 처음부터 다시 하고, 변동 사항이 없으면 아까 하다 말았던 스크롤을 마저 계속하게 코딩을 했다.

오늘날은 단순히 2차원 스크롤을 위해서 저렇게 헝그리 코딩을 할 필요는 없을 것이다. 그러나 화면에다 아주 복잡한 3D 그래픽을 점진적으로 렌더링 하거나, 고해상도 만델브로트 집합 같은 프랙탈 그래픽을 실시간으로 그린다면.. 동일한 테크닉이 여전히 필요할 것이다.

CPU를 많이 소모하는 계산 위주의 작업 말고, 주변 기기와의 I/O 비중이 큰 작업도 생각해 보자. 워드 프로세서에서는 인쇄 중 동시작업(일명 스풀링), PC 통신 프로그램에서는 전화 연결 중에, 업· 다운로드 중에 동시작업.. 지금은 너무 당연해서 일도 아닌 게 옛날 도스 시절에는 해당 프로그램의 완전 첨단 고급 기능이라고 소개되곤 했지 않는가?

Windows는 여러 프로그램들을 동시에 띄워서 구조적으로 동시작업이 기능하다고 하지만, 16비트 시절엔 여건이 도스에 비해 막 좋을 건 없었다. 빡센 작업을 하는 중에도 여전히 사용자 반응성을 잃지 않으려면 message loop 차원에서 PeekMessage와 OnIdle 같은 로직이 추가돼야 하고, 작업 역시 UI의 반응성을 해치지 않을 정도로 연산을 짧게 끊어서 찔끔찔끔 해야 하는 건 변함없었다. 이런 정신없는 상태에서 트리 구조 순회나 순열 생성 같은 건 당연히 쌩 재귀호출로 구현할 수 없으며, 사용자 스택 자체 구현이 필수였다.

더구나 이런 idle time processing은 내가 아닌 Windows 내부의 고유한 message loop 하에서 구동되는 modal 대화상자 내지 메뉴 표시 중에는 중단된다는 문제가 있다. 타이머 메시지는 저렇게 modality와 관련된 끊김 현상은 없지만, CPU를 활용하는 효율이 일반적인 idle time processing 메커니즘에 비해 좋지 못하다.

이런 걸 생각하면 멀티스레드가 없었으면 지금처럼 사용자가 입력하는 텍스트의 맞춤법을 실시간으로 검사해서 빨간줄을 그어 주는 기능, C++ 같은 문맥 의존적인 언어 코드를 사용자가 입력하는 걸 인클루드 파트까지 실시간으로 구문 분석해서 자동 완성과 syntax coloring을 구현하는 건 불가능에 가깝게 힘든 일이 될 수밖에 없을 것이다.

4. 파이버: 스레드의 변종

사실, time slicing을 운영체제가 자기 재량껏 하는 게 아니라 내가 원할 때 하도록 thread의 변종인 fiber라는 게 있다. Windows의 경우, 일단 자기 자신을 일반 스레드에서 fiber로 먼저 변환해서(ConvertThreadToFiber) 초기화를 한 뒤, 다른 파이버들을 생성하고(CreateFiber), 파이버들끼리 필요한 타이밍 때 서로 전환(SwitchToFiber)을 하면서 열심히 제 할 일을 하면 된다.

이 경우 스레드 동기화 같은 건 전혀 필요하지 않으며, 멀티스레딩을 표방하면서도 프로그래밍 패러다임은 멀티스레드 성향이 전혀 아니게 된다. 사실, 이건 유닉스 기반의 서버 프로그램의 포팅을 돕기 위해 일부러 도입된 기능이지 실용적으로 딱히 쓰일 일도 없다. 하지만 복잡한 재귀호출이 여러 곳에서 동시다발적으로 일어날 때 자기 스택 상태를 고스란히 보존하면서 작업 context들을 원하는 때에 전환할 수 있다는 점에서는 뭔가 독특한 용도가 있을 것 같기도 하다.

개인적으로 thread가 원래 실타래라는 뜻이니, 컴퓨터 용어로서 thread는 '일타래'라고 번역해서 쓰면 꽤 그럴싸하겠다고 생각해 왔다. 서로 꼬일 수 있는 것까지도 동일한 개념이니까. 그런데 thread의 변종으로서 아예 '섬유'라는 뜻인 fiber는 우리말로 어찌 번역해야 할지 모르겠다. 우리말 순화· 번역이라는 게 이런 추가적인 조어력과 확장성까지 갖추지는 못하는 편이니 대부분 실패하곤 한다.

오늘날 운영체제에서 module이라는 건 EXE, DLL 등 실행 가능한 코드와 데이터, 리소스가 담긴 한 이미지 파일을 식별하는 개념이다. process는 자신만의 독립된 주소 공간을 가진 실행 공간으로, EXE만이 새로 생성할 수 있다. thread는 한 process 안에서 하나 이상 존재할 수 있는 실행 주체이다.
이들에 비해 instance, task는 좀 16비트스러운 용어이다. 32비트 이상부터는 프로세스들이 기본적으로 자기 주소에서 다 혼자 따로 노는 형태이기 때문에 한 모듈(HMODULE)의 여러 instance (HINSTANCE)라는 개념 구분이 별 의미가 없어져 있다.

운영체제에 따라서는 여러 개의 프로세스도 parent/child 관계를 맺고 job이라는 집단을 형성할 수 있다. Windows도 이를 API 상으로 흉내는 내는 걸 지원하지만 막 널리 쓰이지는 않는다. 마치 C가 함수 안에 함수를 공식적으로 지원하지 않는 것처럼(람다 내지 지역 클래스 같은 편법 말고..), 프로세스들도 굳이 계층 구조가 존재하지 않더라도 뭔가 심각하게 불편하거나 불가능해지는 건 없기 때문으로 보인다.

Posted by 사무엘

2017/11/20 08:38 2017/11/20 08:38
,
Response
No Trackback , 2 Comments
RSS :
http://moogi.new21.org/tc/rss/response/1429

Trackback URL : http://moogi.new21.org/tc/trackback/1429

Comments List

  1. 비밀방문자 2017/11/22 13:42 # M/D Reply Permalink

    관리자만 볼 수 있는 댓글입니다.

    1. 사무엘 2017/11/22 15:31 # M/D Permalink

      우와, 그 책 얼마 만에 다시 듣나 모르겠다..? (10몇 년 전 대학 시절의 전공 서적..)
      님도 컴공이 일취월장하고 있는 게 느껴지는구나? ㅋㅋ

Leave a comment

자동차의 덩치를 소형· 중형· 대형으로 분류할 때 이 등급은 탈 수 있는 인원수에 따른 절대적인 기준일 수도 있고, 승용차나 버스 같은 동일한 형태의 차량 중에서 상대적인 기준일 수도 있다.
예를 들어, 똑같이 5명이 타는 "소형" 승용차이더라도 모닝이나 레이 같은 경차는 소형차요, 아반떼는 준중형, 쏘나타는 중형이다. 그리고 그랜저 정도 되면 준대형이고 제네시스는 소형차 중에서는 대형이다. 하지만 제네시스라고 해서 같은 거리를 가는데 고속도로 통행료가 아반떼보다 더 비싸지는 않다. (경차는 별도의 혜택이 있는 차급이니 논외로 하고.)

승용차는 '스마트 포투' 같은 극단적으로 작은 차를 제외하면 경차라도 일단 4~5인승이다. 왜건· 해치백형 SUV 내지 밴 차량은 맨 뒤의 공간에다 좌석을 추가로 달면 9명 정도가 탈 수 있다. 뒷문은 여닫이가 아닌 미닫이(슬라이딩 도어)가 장착되기도 하며, 승용인지 승합인지 솔직히 좀 알쏭달쏭해진다. 아래의 차는 기아 카니발이다.

사용자 삽입 이미지

그 다음으로 일명 봉고차라고 불리는 승합차는 일단은 좌석이 네 줄 있어서 최대 12명이 타는 게 표준이다. 하지만 세 줄만 있어서 9명이 타는 물건도 있고, 또 과거에 아시아 자동차에서 만들었던 '토픽'이라는 승합차는 이례적으로 줄이 하나 더 있어서 15명이 탈 수 있었다. 참고로 15인승이 1종 보통 면허로 운전할 수 있는 차량의 인원수 한계이다.

사용자 삽입 이미지

이렇게 5인승 승용차보다 사람이 약간 더 많이 탈 수 있는 차량은 자그마한 학원이나 교회에서 수송용으로 운용하기 좋은 물건이다. 그리고 9인승 이상의 차에 6명 이상이 탑승했다면 경부 고속도로에서 버스 전용 차선을 이용할 수 있다.
남산 터널은 승용차라도 3인 이상만 타면 혼잡 통행료가 면제되고, 서울 시내의 중앙 버스 전용 차선은 일단은 오로지 정규 노선 버스 같은 영업용 차량만 이용할 수 있기 때문에 규정이 서로 조금씩 차이가 있다.

승합차보다 더 큰 차가 필요하다면 이제 미니버스 또는 마이크로버스라고 불리는 물건을 살펴볼 차례이다. 버스 중에서는 소형이지만 차량 전체의 덩치 랭크에서는 중형차 급에 속한다.
얘는 이제 한 줄에 좌석이 3개에서 4개로 늘어나며, 차에서 키 170~180급인 성인이 일어서서 차내 복도를 돌아다닐 수 있다. 작고 좁은 좌석에 25명 정도가 탈 수 있으며, 객실 아래의 별도의 짐칸과, 운전석에서 스위치로 곧장 개폐 가능한 자동문도 이 차급에서 최초로 등장한다.

요런 버스는 대중교통에서는 주로 마을버스 형태로 다닌다. 현대 자동차의 브랜드명은 '카운티'이다.

사용자 삽입 이미지

하지만 얘는 오늘날의 대형 버스와 비교하면 여전히 전방엔진이며, 승객이 타는 문은 중문 하나만 존재한다는 차이가 있다. 옛날 버스의 구조와 더 비슷하다.
승합차와는 달리 미니버스부터는 뒷바퀴의 한 축에 타이어가 하나가 아니라 트럭처럼 두 개씩 연결되어 있다. (사실, 기아 자동차 봉고는 승합차 차급인데 1톤 트럭처럼 뒷바퀴가 둘씩으로 구성되어 있었음)

마이크로버스보다 한 단계 더 커진 버스는 35인승 중형 버스이다. 얘는 바퀴의 크기, 차량의 길이와 폭이 대형 버스보다 미묘하게 작다. 사실 마이크로버스와도 구분이 쉽지 않아 보일 정도다. 그래도 얘는 덩치만 살짝 작을 뿐 앞바퀴의 앞에 드디어 폴딩 도어가 달렸으며, 외형이 더 각이 졌고 후방엔진이기까지 하니, 버스로서 갖출 건 다 갖추고 있다. 전체 차급의 관점에서는 준대형 정도 된다.

사용자 삽입 이미지

이것과 다른 중형 버스도 있다. 시내버스 중에 폭과 타이어 크기는 대형 버스와 동일한데 길이만 오리지널 대형보다 약간 짧은 놈을 본 적이 있을 것이다. 하긴, 연세 대학교 셔틀버스도 요런 차종이 다닌다.

사용자 삽입 이미지

일반적인 '45인승'(4*10+5) 대형 버스는 이제 8톤 트럭과 얼추 비슷한 덩치가 되며, 한 줄에 좌석이 5개까지 배치 가능하다. 구체적인 스펙을 접하지는 못했지만 대형 고속버스· 관광버스는 대형 시내버스보다 크기나 엔진 출력이 좀 더 크다고 한다. 아래의 에어로시티를 보면, 위의 중형 버스인 그린시티와 길이가 어떻게 차이가 나는지를 알 수 있다

사용자 삽입 이미지

좌석을 일반이 아닌 우등 형태로 배치하면 '28인승'(3*8+4)이 되는데, 일부 시외버스는 좌석의 폭은 우등과 동일하지만 간격은 약간 조밀하게 해서 31인승을 구현하기도 했다.

45인승보다 더 큰 버스는 차축이 더 늘어나고 굴절 또는 2층 형태가 된다. 우리나라는 요 얼마 전부터 일부 경기도 광역버스에 2층 버스가 도입된 정도이지 차내에 화장실이 있거나, 운전사가 두 명 타서 정기적으로 교대 근무를 하거나(짐칸 옆에 교대 운전자용 간이침실이..), 엔진룸이 차체 앞에 달린 경우는 없다. 제일 큰 이유는 물론 국토가 그 정도로 장거리 운행 최적화 디자인이 필요할 정도로 크고 아름답지 않기 때문이다.

오히려 우리나라에 고속도로가 처음으로 생겼던 1970년대에는 미국의 유명한 버스 회사인 그레이하운드 사가 국내에도 진출했으며, 그때는 미국 스타일의 차축 3개 + 일부 2층에 화장실까지 달린 버스가 잠시 다니긴 했다. 비행기로 치면 팬암 사가 한국에 진출해서 광고를 내던 시절 같다.

사용자 삽입 이미지

그러다가 그 회사가 한국에서 철수하고, 버스 안에 굳이 화장실을 설치하느니 그냥 휴게소에 정차하면 되고, 도로의 상태와 차량의 성능도 향상되면서 흑역사가 된 것이다. 철도에서 야간 열차가 갈수록 없어지고, 침대차가 정규 운행 노선에서 퇴출된 것과 동일한 이치이다.

단, 에버랜드에서 정문과 주차장 사이를 오가는 셔틀버스는 참 인상적이다. 차축이 3개이며 전문 중문 후문이 다 존재하여 거의 굴절 버스에 맞먹는 덩치이지만, 그렇다고 중간에 굴절이 있지는 않다.

사용자 삽입 이미지

에버랜드 셔틀버스는 덩치가 너무 커서 우리나라 현행법상 일반 도로를 주행할 수 없는 차량이라고 한다. 차량으로 등록할 수가 없어서 법적으로는 '놀이기구'로 등록했으며, 번호판 자리에는 '구내운송용'이라는 팻말이 달려 있다. 이 버스들은 주차장과 정문 사이의 셔틀버스 전용 도로만 오가며, 일반 도로에서는 일체 주행하지 않는다.

역시 삼성빨로 이런 특이한 차량도 들여올 수 있었나 하는 생각이 들었다.
하긴, 공항 활주로에서 비행기와 여객 터미널 사이를 오가는 단거리 셔틀버스도 저렇게 성격과 용도가 특이한 차량이며, 인천 공항은 장기 주차장과 여객 터미널을 오가는 무료 셔틀버스가 다니기도 한다. 주차장과 본 건물 사이에 버스가 다닐 정도로 거대한 시설은 인천 공항과 에버랜드 말고 국내에 또 있는지 궁금하다.

한편, 버스와는 달리 트럭은 대형 버스보다 작은 차종에도 추가적인 차축이 달린 게 많다. 특히 4~5톤급 중형 트럭에서 들었다 놓았다 하는 가변 차축의 형태로 말이다. 이렇게 차축이 더 달리면 4.5톤 덩치의 트럭에다가도 한 8톤 정도는 그냥 실을 수 있다.
이런 식으로 짐을 왕창 실으면 축중 하중이 여러 개로 분담되는 덕분에 도로 파손이라는 관점에서의 과적 단속에는 안 걸릴 수 있다. 하지만 엔진 출력과 브레이크는 여전히 4.5톤 기준이기 때문에 차량이 무리를 받는 건 어쩔 수 없다.

* 추가 설명: 자동문

버스에 존재하는 자동문은 시내버스에서 안내양을 퇴출시키는 데 큰 기여를 한 물건이다. 얘는 사람의 힘으로 여닫는 승용차 문들과는 달리, 뭔가 철컥 걸린 채로 꼭 닫아야 한다는 단서가 없다. 차를 타면 일반적으로 "문이 완전히 안 닫혀서 도어 경고등이 여전히 켜져 있으니 다시 똑바로 닫으세요" 이걸 신경 써야 하지만, 자동문은 그렇지 않다는 것이다. 문과 차체의 부품이 기계적으로 연결되고 걸린 것에 의존하지 않고, 공기압 같은 외력에 의해 문이 닫힌 상태가 계속 유지되고 있기 때문이다.

이런 '걸림' 구조(충분히 세게 꽝 닫아야 하는 것)랑 '자동문' 메커니즘이 꼭 일대일 동치 관계인 것은 아니다. 자동문이야 자체적인 동력으로 문을 붙잡고 있는 게 '걸림' 구조와 연동하는 것보다 더 쉬우니까 일반적으로 걸림 구조를 채택하지 않는 것일 뿐이다.
그렇기 때문에 에쿠스 내지 오늘날의 EQ900 같은 호화 고급차는 트렁크 정도에는 자동 개폐 장치가 달려 있다. 롤스로이스는 승용차이지만 아예 출입문도 자동 개폐 가능하다.

그리고 소형 승합차는 원래는 자동문이 없지만 3rd-party 업체에서 만든 자동문 시스템이 추가 장착되기도 한다. 옛날에, 대략 10년쯤 전에 1시간 간격으로 대전 지하철 월평 역에서 출발하던 KAIST 행 셔틀버스가 그랬다.
봉고차 크기이지만 좌석은 마치 우등 고속 좌석처럼 1인석 위주로 띄엄띄엄 리모델링하고, 운전사가 일괄적으로 문을 개폐할 수 있게 자동문 장치를 달아 놓은 형태였다. (직접 보지는 못했지만 지금은 25인승 미니버스로 차의 크기가 업그레이드 된 모양이다.)

* 잡설: 버스와 지하철의 차이

대중교통으로서 지하철에는 없고 버스에만 있는 것 중 하나는 바로 라디오 방송이지 싶다. 사용자 경험 측면에서 굉장히 큰 차이가 아닐 수 없다.
"잠깐만~! 우리 이제 한번 해 봐요 사랑을 나눠요.." 이런 CM송으로 끝나는 무슨 공익광고? 미담 사례 방송은 25년쯤 전에 나 초딩 때도 들었던 것인데 지금도 똑같이 흘러나오는 걸 우연히 들었다. 옛날에는 "기아자동차 협찬" 이러던데.. 물론 그건 IMF 이전의 정말 옛날 얘기이다.

한편, 지하철에는 버스에는 없는 잡상인이 종종 등장한다. 그리고 문 곁에 서 있는 사람 때문에 승하차 무질서가 야기되는 편이다.
이건 자동차로 치면 횡단보도나 교차로 근처에 불법주차된 차들 때문에 차량 통행이 불편해지고 사고의 위험이 증가하는 것과 같다. 이들 때문에 하차 승객이 나가기 어려우며, 심지어 동일한 문에서 승차와 하차가 동시에 진행(!)되면서 문의 양쪽에 서 있던 승객이 공평하게 승차하지 못하게 된다. 이 말인즉슨, 둘 중 한쪽은 좌석에 앉을 가능성을 공평하게 얻지 못한다.

이런 지하철과 달리, 버스는 예측 가능한 정해진 위치에 정차하지 않는 게 문제이다(대로변에 버스 여러 대가 동시에 많이 들어오는 정류장 기준). 이 때문에 미리 줄을 서서 기다리기가 어려우며 더 큰 무질서가 야기된다.

Posted by 사무엘

2017/11/17 08:26 2017/11/17 08:26
,
Response
No Trackback , No Comment
RSS :
http://moogi.new21.org/tc/rss/response/1428

Trackback URL : http://moogi.new21.org/tc/trackback/1428

Leave a comment

1. 교사와 교수의 차이, 교육 체계 관련

교사는 이미 주어진 교과서와 교육과정대로만 가르쳐야 하는 사람이지만, 교수는 자기가 독자적인 강의 계획표를 짜고 교재도 선택해서 전적으로 자기 재량껏 학생들을 가르칠 수 있다.
교사는 한 교무실에서 자기 자리가 있지만, 교수는 각 개인이 법적으로 걸어다니는 교육기관이며 자기 연구실이 따로 있다.

더 근본적으로.. 교수는 각 학문의 최전선에서 새로운 지식· 학설· 기술을 연구 개발하고 논문으로 발표하는 게 업인 사람이다. 학교에서 교사들이 가르칠 거리들을 만들고 정하는 사람이 교수이다. 글쎄, 현실에는 자질 미달인 교수도 있고 정년 보장만 딱 받은 이후부터 능력 파탄· 인성 파탄· 정신줄 다 놔 버린 교수도 일부 있겠지만, 교수의 원론적인 직무는 저렇다는 뜻이다.

물론 교육과정대로만 가르치는 일도 보통일이 아니니, 교사만 해도 일반인 평균 이상의 지능과 인성, 학력과 체력, 리더십이 필요한 직업이다. 어느 사회와 문명에서나 교사가 생업 전선 안 뛰어들고도 안정된 소득과 지위를 보장해 주는 좋은 직업인 건 이런 이유 때문이다.
만원 버스를 타면 여기에 탄 승객들은 다 교사 자격증 소지자 내지 박사들이고, 가끔 가뭄에 콩 나듯이 좌석 승객이 내려서 자리가 생기는 건 교수· 교사 자리와 같지 않나 생각하곤 했다.

또한 교사는 학생들 앞에서 권위도 필요하다. 교사와 교수 같은 교원은 범죄를 저질렀다 해도 무슨 교실에서 학생을 대놓고 성추행 하거나 죽이기라도-_- 해서 현장에서 당장 저지해야 하는 급박한 상황이 아닌 이상, 수업 중에 학생들이 보는 앞에서 체포되지는 않게 법으로 보장돼 있다.

하긴, 옛날엔 어떤 현직 교사가 도박 혐의로 경찰에 체포됐는데.. 취조를 담당하는 형사가 우연히도 그 선생의 옛 제자였던 일도 있었다..;; 그래서 그 형사는 민망한 나머지 황급히 저 피의자의 담당 형사를 자기 말고 다른 사람으로 바꿔 달라고 요청해야 했다.

의학에서 소아과에는 "소아는 덩치만 작은 성인이 절대 아닙니다" 이런 금언이 있다. 어린아이는 몸이 돌아가는 구조가 의학적으로 차이가 많이 나니, 성인에서 물질대사 규모만 줄인 급으로 생각해서는 안 된다는 뜻이다.

교육도 마찬가지이다. 초등교육은 대학교 이상의 고등교육보다 마냥 쉽고 열등하고 하위 호환 관계에 있는 것이 절대 아니다. 내가 생각하기에는 이런 관계인 것 같다.
아이콘을 그리거나 글자를 찍는데, 초등교육은 10픽셀~20픽셀 같은 아주 작은 픽셀에다 그리는 것과 같다. 공간이 작으니까 쉽게 그릴 수 있을 것 같냐고? 천만의 말씀이다. 이렇게 작은 공간에다가는 큰 그림을 기계적으로 축소한다고 해서 절대로 보기 좋은 아이콘을 만들 수 없다. 정보량 자체가 아주 작으니 대충 그리는 건 금방 가능할지 모르나, 고퀄로 만드는 것은 절대 만만한 일이 아니다.

만화에서는 사람의 눈만 엄청 크게 그리듯, 이렇게 작은 공간에는 사람이 중요하게 인지하는 부분만 강조해서 아예 별도의 그림을 그려야 한다. 글자의 경우도 픽셀의 배치가 단 1만 차이가 나도 그 여파가 굉장히 커지기 때문에 아주 심혈을 기울여서 획을 그려야 한다. 폰트에도 쑤제 힌팅이 괜히 존재하는 게 아니다. 기계의 자동화가 불가능한 영역이 있기 때문이다.

그러다가 중등을 거쳐서 고등교육으로 가면 그냥 닥치고 수백~수천 픽셀에서 최고화질의 그림을 그리는 것과 같게 된다. 현업 최전선에서 그림의 화질을 조금이라도 더 올리려고 난리를 치는 게 고등교육이 하는 일이다.
그리고 수십~100픽셀 이상 정도 크기부터는 굳이 크기별로 일일이 그림을 따로 그릴 필요 없이, 최고화질 그림을 축소하는 것만으로도 충분하며, 글꼴에서도 힌팅이 별로 필요하지 않게 된다. 수백 픽셀 이상부터는 아마 산술적인 anti-aliasing조차도 별 필요가 없어질 것이다.

교육과정의 수준도 단계별로 이런 식으로 성격이 다르기 때문에 초등학교 교사와 중등학교(중· 고등) 교사는 서로 호환되지 않는 것이라 볼 수 있다. 대학 교수는 두 말할 필요도 없고 말이다.
육상 경기도 100미터나 200미터는 크라우칭(엎드린) 스타트에 뒷바람이던가 어느 풍속 이상으로 분 건 인정 안 하고 굉장히 까다롭지만.. 수 km 내지 마라톤 같은 장거리에서는 스타트가 별로 중요하지 않으니 여러 사람들이 그냥 선 채로 떼거지로 설렁설렁 출발한다. 이런 차이에다가도 비유할 수 있을 것 같다.

한편, 대학교 정도가 되면 의무교육도 아니고 학생도 반쯤 성인이며 굳이 "인간 되는 참교육"보다는 선생과 학생이 상업적인 거래를 하는 관계에 더 가까워진다. 학원과 얼추 비슷하지만 그래도 학원보다는 더 전문적이고, 실무보다는 일단 이론 위주의 학술 교육이 행해진다. (일단은 설립 취지가..) 대학 교수가 애들 군기를 잡고 생활 지도를 한다거나 하지는 않는다.

그러나 그 전의 교육 단계에서는.. 아무래도 어느 정도 강제성을 부여해서 선생이 학생들을 꽉 잡고 있는 게 필요하다. 그렇지 않고 선생이 누구 말마따나 노조 설립까지 가능한 근로자이고 학생은 '고갱님'이어서 자기 귀에 맞는 선생을 언제든지 취사선택하는 것은... 교육적으로 좋은 모습은 아니어 보인다. 아무리 자격 이하의 불량교사로 인한 폐단이 있다 하더라도 교권 자체를 부정해 버리면.. 인간 안 된다. 그러니 학교와 관련된 사회 문제가 해결하기가 쉽지 않고, 또 학교에 암약해서 불량 이념을 애들한테 주입하는 교사도 심각한 사회 문제가 아닐 수 없다.

2. 미혼과 기혼의 차이

미혼자와 기혼자의 처지 차이는 자동차에다 비유하면 이렇게 설명할 수 있을 것 같다.
미혼자는 처자식이 딸린 게 없기 때문에 매우 자유롭고 경제적인 부담이 덜하다. 이것은 자동차가 엔진이 돌아가지만 기어가 중립이어서 힘이 바퀴에 걸리지 않은 상태와 같다.
이 상태에서는 가속 페달을 정말 조금만 밟아도 '웽~~!!' 소리와 함께 엔진 회전수가 치솟는다. 그러나 페달에서 발을 떼는 순간 엔진 회전수 역시 곧장 곤두박질치면서 다시 공회전 상태로 돌아온다.

기혼자는 기어가 D로 들어가서 엔진의 힘이 바퀴에 전해지고 자동차가 앞으로 나아가는 것과 같다. 엔진이 굉장한 부하를 받고 있는 관계로, 액셀을 같은 강도로 밟으면 중립일 때보다는 엔진 회전수가 훨씬 더 더디게 증가한다.
그러나 이제는 엔진만 바퀴를 굴리는 게 아니라 바퀴가 굴러가는 관성도 엔진의 회전을 어느 정도 유지시켜 준다. 그렇기 때문에 주행 중에는 액셀에서 발을 떼더라도 엔진 rpm이 바로 곤두박질치지 않고 있다가 아주 서서히(평지 기준) 감소한다.

이 차이가 사람의 인생에서 무엇을 의미하는지 감을 잡을 수 있을 것이다.
그리고 자동차가 실제로 굴러가서 일을 하고 자동차의 존재 목적을 실제로 수행하려면 결국은 N에만 머물러 있는 게 아니라 D에서 주행을 하긴 해야 할 것이다.

교회에서도 홀몸인 2, 30대 청년일 때야 체력과 지능이 최고 뛰어난 시절이고, 직장 다니면서 돈도 벌 테니 얼마든지 교회 일을 별 부담 없이 수행할 수 있다. 하지만 그건 제풀에 꺾이기도 쉽다. 이것은 마치 N 상태에서 액셀 페달을 밟았다가 떼는 것과 같다.

그 성경적인 사고방식이 자기 평생을 함께할 배우자를 고를 때에도 동일하게 작용하고, 결혼과 가정이라는 어마어마한 부담이 지워진 뒤에도 변함없이 교회를 섬길 수 있을 때에야 그 신앙심이 진정 레알이라는 것을 입증할 수 있을 것이다. 그리고 배우자를 잘 만났다면 자신의 영적 상태를 배우자가 같이 돕고 유지시켜 주기도 할 것이다. 바퀴도 엔진을 퓨얼컷 상태에서 자연스럽게 회전시켜 주는 것처럼 말이다. 뭐 운전하면서 갑자기 이런 생각이 들었다.

자동차의 엔진에 가해지는 부하의 강도는 위에서 아래로 갈수록 커진다.

  1. 애초에 엔진이 바퀴와 연결되지도 않은 채(기어 중립) 그냥 엔진 혼자 도는 것 (아무 부하 없음)
  2. 엔진과 바퀴가 연결은 됐지만 차체가 공중에 들려서 바퀴가 혼자 도는 것 (구동축 자체의 무게 말고 다른 부하 전무)
  3. 바퀴가 지면과 접촉하여 차체를 지탱하면서 돌지만, 바퀴와 닿아 있는 지면의 궤도만 돌아가고 차체 자체는 움직이지 않는 것 (그러면 바퀴가 아무리 고속으로 돌아도 공기 저항 받는 게 없음)
  4. 바퀴가 굴러가면서 차체가 그대로 움직이는 것 (실제 주행. 부하가 가장 큼)

3. 남이 올려 줘야 올라갈 수 있음

자동차의 원리를 통해서 알 수 있는 인생의 원리는..
먼저 저단에서 엔진이 열심히 돌아서 rpm이 웽~~ 올라가야 더 높은 단으로 변속이 되고 차가 속도를 계속 낼 수 있다.
"쳇 겨우 1단? 쒜빠지게 몇천 rpm으로 돌아 봐야 시속 30도 채 못 낼 텐데 왜 돌아?" 이런 마인드로는 차가 결코 제대로 달릴 수가 없다.

사람은 모름지기 낮은 지위, 덜 중요하고 남이 안 알아주는 위치에 있을 때부터 자기 직분에 신실하고 성실해야 한다. 그래야 점차 더 화려하고 중요한 자리로 올라가고 책임감 큰 직분이 주어지고, 연봉도 덩달아 뛰게 된다.

남이 당신에게 보상을 주는 게 먼저가 아니라, 당신이 노오력하고 애쓰는 게 먼저다. 이것은 성경에도 거듭해서 등장하는 철칙 중의 철칙이다(눅 19:17, 눅 16:10, 눅 14:10, 마 25:23). 가령, 박봉 탓을 하기에 앞서 자기가 먼저 자기 월급보다 회사에 더 기여해야 한다.
상식적으로 당신이 무슨 기업의 경영자라든가 높은 사람 자리에 있어 봐도.. 누구한테 중요한 일을 맡기고, 누구에게 기업 기밀과 핵심 기술을 알려주고 궁극적으로 기업의 후계자로 삼고 싶겠는가? 답이 뻔한 노릇이다.

물론, 예외 없는 규칙 없다고, 이 악한 세상에서 당신의 노력이 반드시 금방 인정받고 보상으로 돌아온다는 된다는 법은 없다.
성실한 근로자를 호구로 삼아서 열정페이 착취를 일삼는 악덕업주가 없다는 얘기는 아니다. 좌익들도 맨~날 이런 극단적인 예외 사례만 부각시키면서 반정부 반기업 선동을 벌인다.
허나 그건 법대로 처분하고 통계상의 outlier 상으로 생각할 문제이지 세상 전체에는 아직도 자기 월급보다 직원 월급을 더 생각하는 선량한 기업주가 더 많다.

이것이 인생이다.

4. 참교육

성경에 나오는 '참교육'이란 이런 거다.

"기드온이 이르되, 이런 까닭에 {주}께서 세바와 살문나를 내 손에 넘겨주신 뒤에 내가 '들가시와 찔레'로 너희 살을 찢으리라, 하더라." (삿 8:7)

그 뒤... 그런데 그것이 실제로 일어났습니다. 기드온은..

"그 도시의 장로들을 붙잡은 뒤 '들가시와 찔레'를 취하여 그것들로 숙곳 사람들을 가르치고" (삿 8:16)

기드온은 어렵고 위급할 때 자기를 무시하고 깔봤던 사람들을 예고했던 대로 그대로 되갚아 줬다.
타 성경들은 그냥 분위기 대로 응징, 징벌했다, punish, 방법(...!)했다.. 이런 식으로 번역했지만, 킹 제임스 성경만은 저걸 '가르쳤다' taught라고 번역했다.
기드온이 가시가 숭숭 박힌 식물 줄기를 폼으로만 들고 다니면서 무슨 강의를 했을 리는 만무하고 말 그대로 거기 사람들을 붙잡아서 자기가 말했던 대로 행했다.

"인생은 실전이야 이 존만아~" (퍽~퍽~)
"아 X발, 누구든지 작은 기드온을 건드리면 X되는구나, 아주 X되는 거구나.. ㅠㅠ"

그러니 당사자들은 이걸 가시에 찔리면서 피눈물을 흘리면서 깨우치게 됐고, 성경은 그걸 '가르쳤다/가르침을 받았다'라고 표현했으니 이 얼마나 흥미로운 일인가?
일진들을 참교육 시키는 걸로 유명한 천10호 천 종호 판사 아저씨의 호통 따위는 그냥 약과다.

똑같이 애를 두들겨 패도 사랑의 체벌과 아동 학대는 종이 한 장 차이이다.
똑같이 사람을 죽여도 누가 무슨 명분으로 죽이느냐에 따라 한쪽은 나라를 지키는 숭고한 행동이거나 사회 정의를 행하는 사형 집행인 반면, 다른 한쪽은 흉악 범죄인 것이다. 정말 똑같은 화학 작용인데 발효와 부패의 차이와도 같다고 봐야 할 듯하다.
그리고 이 사회는 필요악만 없애고 절대악은 그대로 방임하고 놔두는 지경으로 가고 있다. 인간이 하나님보다 자비· 자애로운양 코스프레 해서 인간에게 좋을 건 하나도 없다.

Posted by 사무엘

2017/11/14 19:32 2017/11/14 19:32
, , ,
Response
No Trackback , a comment
RSS :
http://moogi.new21.org/tc/rss/response/1427

Trackback URL : http://moogi.new21.org/tc/trackback/1427

Comments List

  1. 우익 2017/11/15 07:35 # M/D Reply Permalink

    님이 생각하는 좌익은 무엇인가요?

Leave a comment
« Previous : 1 : 2 : 3 : 4 : 5 : ... 135 : Next »

블로그 이미지

철도를 명절 때에나 떠오르는 4대 교통수단 중 하나로만 아는 것은, 예수님을 사대성인· 성인군자 중 하나로만 아는 것과 같다.

- 사무엘

Archives

Authors

  1. 사무엘

Calendar

«   2017/12   »
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

Site Stats

Total hits:
883306
Today:
235
Yesterday:
416