기본 콘텐츠로 건너뛰기

추천 가젯

Tmux 환경에서 Vim 컴파일 시 발생하는 termio/termios 감지 오류 해결 방법

 리눅스 환경에서 소스코드를 직접 빌드하다 보면 의외의 환경 변수나 터미널 세션 설정 때문에 엉뚱한 빌드 에러를 마주할 때가 있습니다. 대표적인 예로 Tmux 세션 내부에서 Vim 소스를 컴파일할 때 발생하는 termio/termios 감지 오류 가 있습니다. 이번 글에서는 해당 에러가 발생하는 원인과, 단순한 clean 으로는 해결되지 않는 이유 및 올바른 해결 방법을 정리합니다. 1. 문제 원인 Vim의 소스 코드 빌드 과정( configure )은 시스템이 System V 계열인지 Linux 계열인지 판별하기 위해 termio.h 와 termios.h 헤더 파일 및 터미널 인터페이스를 검사(Probe)합니다. 하지만 Tmux 내부(세션 안)에서 컴파일을 진행할 경우 , Tmux가 제공하는 PTY(Pseudo-Terminal) 환경과 TERM=screen 등의 특수한 환경 변수 영향으로 인해 Autoconf가 터미널 인터페이스를 검출하는 과정에서 오동작을 일으킵니다. 그 결과, 실제 시스템 조건과 무관하게 설정 에러를 발생시키게 됩니다. 2. 왜 make clean 으로는 해결되지 않을까? 일반적인 개발 과정에서는 빌드가 꼬였을 때 make clean 을 실행하곤 합니다. 하지만 make clean 은 컴파일된 오브젝트 파일이나 바이너리( .o 파일 등)만 삭제할 뿐, Autotools가 시스템 환경을 탐색한 결과로 남긴 캐시( config.cache 또는 내부 매크로 변수)나 설정 파일들은 그대로 유지 합니다. 일반적인 상황에서는 시스템의 하드웨어/OS 정보가 바뀌지 않기 때문에 이 잔여물이 문제가 되지 않습니다. 그러나 Tmux나 Screen 같은 터미널 멀티플렉서 환경에서 탐색된 왜곡된 정보가 캐시에 박혀버리면, 나중에 Tmux 외부(일반 터미널)로 나와서 빌드를 시도해도 이전의 오염된 캐시 때문에 계속해서 오류가 발생하게 됩니다. 3. 해결 방법 이 문제를 해결하기 위해서는 반드시 Tmux 외부 환경 에서 기존의 오염된 설정 파일을 ...

CPP> std::lock_guard 뮤텍스 활용법.

CPP은 직접 메모리를 할당하고 제어하다보니, 포인터를 사용하여 힙에 메모리를 할당한 후,
해당 주소를 반환해서 쓰는 경우가 많다.


그렇다보니, 잠깐 뭔가를 하는 경우에도, new로 클래스를 할당하고, 끝날 때 delete를 호출해야하는 경우가 발생했다. 

그런데, 이 delete를 호출하기전에, 중간에 return이 되는 경우와 같이 delete가 호출되지 않거나, 코드 작성자가 까먹거나 하는 일이 생기는데, 매번 new가 호출될 때마다, 메모리가 할당되므로

여러번 호출되는 함수에서 이런 실수가 발생하면 해당 프로세스가 메모리를 점점 잡아먹다가, 시스템을 먹통이 되게 만들거나, OS에서 해당 프로세스를 정지하거나 하는 등, 정상적인 작동을 하지 못하게 된다. 이것을 메모리 누수라고 부르는데, 

이 메모리 누수를 막기 위해, 보통의 지역변수들처럼, 스택에서 무언갈 하다가, 스택이 pop되면 delete를 자동 호출하기 위해, 스마트 포인터라는 것이 도입 되었다.  실제로는 굉장히 복잡하겠지만 간단히 설명하자면 다음과 같다. 
template<class T> 
class smart_p {
    public:
        T* ptr; 
        operator= (smart_p<T> a, T* b){
            ptr = b;
        }
        smart_p(T* b) {
            ptr = b;
        }
        void ~smart_p() {
            delete ptr;
        }
}
new에서 반환하는 메모리 주소를 받아다가 내부 메모리 주소를 저장하는 클래스를 만들고 클래스를 스택에 만들어 사용하는 것이다. 
그러면 스택에 끝에서 자동으로 메모리의 해제가 발생한다. 

시작이 있으면 반드시 끝이 있어야 하는 것 가운데에는 mutex라는 것도 있다.
mutex는 lock을 걸어주면 반드시 unlock을 걸어주어야, 다른 프로세스가 일하기를 대기하다가 일을 시작할 수가 있다, 

메모리 누수는 서서히 시스템이 죽어가지만 mutex를 unlock하지 않으면 그냥 시스템이 죽는다. 

mutex도 스마트포인터처럼 같은 스택에 클래스를 만들어 사용할 수 있다. std::lock_guard이 그와 같은 일을 한다.  스마트 포인터는 메모리 생성은 그래도 직접 new를 호출하는 방식을 많이 사용했는데, (아무래도 팩토리 방식을 쓸 수도 있으니까)

mutex는 lock_guard도 직접 거는 방식을 사용한다. 대략 간단히 쓰자면 다음과 같겠지.

template<class T> 
class lock_guard {
    public:
        T& m; 
      
        lock_guard(T& b) {
            m = b;  m.lock(); 
        }
        void ~lock_guard() {
            m.unlock();
        }
}

그 외,std::lock이라는  여러개의 mutex를 동시에 받아서 lock을 걸 수도 있다. 

문서를 읽어보자.

각각의 lock을 직접 건다면, 사용 방법에 따라, ABC, BAC 순인 lock이 걸릴 때,

상호간 무한 대기상태에 빠질 수 있으므로 이런 방법을 사용한다.
(두 항목들간 복사 같은 상황) 

실제 구현은 std::atomic 등을 사용해, 락을 동시에 거는 방법 등을 사용하는 것이 아닐까!,  추측한다. 

댓글

  1. 스마트포인터는... 이제 저기에 레퍼런스 카운터 같은거 붙기 시작하면 덕지 덕지 복잡해 진다.

    답글삭제

댓글 쓰기