Ctrl + C 키 이벤트 가로채기

|

Linux에서 작동하는 코드입니다. (Cygwin에서 빌드하면 윈도우에서도 작동합니다.)

기본적으로 Ctrl + C 키를 누르게 되면 프로그램이 강제로 종료되는데, 프로그램이 종료되기 전에 뭔가 처리해야 할 요소가 있다면 아래의 코드를 이용해서 Ctrl + C 키 이벤트를 가로챌 수 있습니다.

예제 코드

#include <cstdio>
#include <sys/stat.h>
#include <cstdlib>
#include <unistd.h>

void (*breakCapture)(int);

void signalingHandler(int signo) {
  printf("'Ctrl + C' processing...");

  exit(1);
}

using namespace std;

int main(void) {
  printf("Hello SnowDeer.\n");

  setsid();
  umask(0);

  breakCapture = signal(SIGINT, signalingHandler);

  while(true) {
    printf("Hello...\n");
    sleep(1);
  }

  return 0;
}

실행 화면

image

Message 및 Message Queue

|

메세지(Message)와 메세지큐(MessageQueue)는 이벤트(Event)들을 한 곳에서 처리하거나 멀티 쓰레드(Multi-thread) 환경에서 쓰레드간 이벤트를 전달할 때 유용하게 사용됩니다.

C++로 구현된 메세지 및 메세지큐 예제입니다. 헤더 파일로만 이루어져 있어서 include 만으로 사용가능합니다. 또한 하단부에는 메세지와 메세지큐를 활용한 메세지 핸들러(Message Handler) 코드가 있습니다. 안드로이드의 핸들러(Handler)와 유사한 구조로 되어 있습니다.


Message.h

#ifndef SNOWDEER_MESSAGE_H
#define SNOWDEER_MESSAGE_H

class Message {
 public:
  Message(int _what) : what(_what), arg1(0), arg2(0) {}
  Message(int _what, int _arg1) : what(_what), arg1(_arg1), arg2(0) {}
  Message(int _what, int _arg1, int _arg2) : what(_what), arg1(_arg1), arg2(_arg2) {}
  virtual ~Message() {}

  int what;
  int arg1;
  int arg2;

  const static unsigned int MESSAGE_CLIENT_SOCKET_THREAD_CLOSED = 100;
};

#endif //SNOWDEER_MESSAGE_H


MessageQueue.h

#ifndef SNOWDEER_MESSAGEQUEUE_H
#define SNOWDEER_MESSAGEQUEUE_H

#include <queue>
#include <mutex>
#include <condition_variable>

using namespace std;

template<class T>
class MessageQueue {
 public:
  MessageQueue(void) : mQueue(), mMutex(), mCondition() {
    mIsLoop = true;
  }

  ~MessageQueue(void) {
  }

  void clear() {
    std::lock_guard<std::mutex> lock(mMutex);
    std::queue<T> emptyQueue;
    std::swap(mQueue, emptyQueue);
  }

  void enqueue(T t) {
    std::lock_guard<std::mutex> lock(mMutex);
    mQueue.push(t);
    mCondition.notify_one();
  }

  void destory() {
    mIsLoop = false;
    mCondition.notify_one();
  }

  T dequeue(void) {
    std::unique_lock<std::mutex> lock(mMutex);
    while((mIsLoop)&&(mQueue.empty())) {
      mCondition.wait(lock);
    }
    T val = mQueue.front();
    mQueue.pop();
    return val;
  }

 private:
  std::queue<T> mQueue;
  mutable std::mutex mMutex;
  std::condition_variable mCondition;
  bool mIsLoop;
};

#endif //SNOWDEER_MESSAGEQUEUE_H


MessageHandler.h

#ifndef SNOWDEER_MESSAGE_H
#define SNOWDEER_MESSAGE_H

class Message {
 public:
  Message(int _what) : what(_what), arg1(0), arg2(0) {}
  Message(int _what, int _arg1) : what(_what), arg1(_arg1), arg2(0) {}
  Message(int _what, int _arg1, int _arg2) : what(_what), arg1(_arg1), arg2(_arg2) {}
  virtual ~Message() {}

  int what;
  int arg1;
  int arg2;

  const static unsigned int MESSAGE_CLIENT_SOCKET_THREAD_CLOSED = 100;
};

#endif //SNOWDEER_MESSAGE_H


MessageHandler.cc

#include "MessageHandler.h"

MessageHandler::MessageHandler() {
  mIsRunning = false;
}

MessageHandler::~MessageHandler() {}

void MessageHandler::start() {
  mIsRunning = true;
  mLooper = std::thread(&MessageHandler::loop, this);
}

void MessageHandler::stop() {
  mIsRunning = false;
  if(mLooper.joinable()) {
    mLooper.join();
  }
  clear();
  mMessageQueue.destory();
}

void MessageHandler::sendMessage(shared_ptr<Message> message) {
  mMessageQueue.enqueue(message);
}

void MessageHandler::clear() {
  mMessageQueue.clear();
}

void MessageHandler::loop() {
  while(mIsRunning) {
    shared_ptr<Message> message = mMessageQueue.dequeue();

    if(mIsRunning == false) {
      break;
    }

    switch(message->what) {
      case 1:
        break;

      case 2:
        break;
    }
  }
}

프로세스 관리하기

|

리눅스 프로세스

용어 설명
PID (Process ID) 프로세스 고유 식별 번호
UID (User ID) 프로세스를 소유한 사용자 계정의 식별 번호
GID( Group ID) 프로세스가 속해있는 그룹의 식별 번호
File Descriptor 프로세스의 읽기/쓰기를 위해 어떤 파일의 어떤 위치를 열고 있는지 기록


#프로세스 확인

현재 실행중인 프로세스는 ps 명령어를 이용해서 확인할 수 있습니다. ps만 입력한 경우 현재 로그인한 사용자가 실행한 프로세스만 보여줍니다.

-a 옵션을 붙이게 되면 다른 사용자의 프로세스 상태도 표시하며, -x 옵션은 화면에 보이지 않는 프로세스까지 모두 표시합니다. -u 옵션을 붙이면 프로세스를 사용한 사용자가 누구인지, 그리고 실행 시간까지 표시합니다.

아래와 같은 형태로 3가지 옵션을 모두 적용할 수 있습니다.

ps -aux

-aux 옵션 대신 -ef 옵션을 붙이게 되면 PID(Process ID)로 정렬된 결과를 보여줍니다.


프로세스 전체적인 상태 조회

ps -aux 명령어 대신 top 명령어를 이용할 경우 실시간으로 메모리 점유율이나 CPU 사용율을 화면에 보여줍니다. ps 명령어가 개별 프로세스의 상태를 보여주는데 반해, top는 전체 프로세스 상태를 한 눈에 보기 좋게 출력합니다.


프로세스 종료하기

프로세스 종료는 kill 명령어를 이용해서 종료할 수 있습니다. 사용법은 다음과 같습니다.

kill -[시그널] [PID]

ex) kill -9 5678

kill은 프로세스의 종료만을 위해 사용되는 명령어는 아닙니다. 현재 실행중인 프로세스에 시그널(Signal)을 보내서 프로세스의 상태를 변경하는 것이 주 목적입니다.

아무 시그널 옵션도 주지 않은 상태로 kill 명령어를 수행하면 시그널의 기본값이 -15로 설정됩니다. 15SIGTERM으로 프로세스를 종료하라는 신호입니다. 대부분의 프로그램은 기본값으로 종료가 되지만 간혹 종료가 되지 않는 프로그램들도 있습니다. 이런 경우는 SIGKILL 시그널인 -9 옵션을 이용해서 프로세스를 강제로 종료하게 할 수 있습니다.

Cygwin vs MinGW

|

개인용 노트 PC에 C++ 개발 환경을 설정하기 위해서 CygwinMinGW을 각각 설치해보면서 어떤 것이 더 좋을 지 테스트를 해보았습니다. 사실 Windows 환경에서는 Visual Studio 하나면 C++ 개발 환경은 거의 끝이지만, 최대한 Linux 환경과 비슷하게 만들기 위해서 MinGW와 Cygwin을 살펴보았습니다.


Cygwin vs MinGW

Cygwin과 MinGW는 둘 다 태생은 비슷합니다. Cygwin은 Windows에서 Linux 환경을 에뮬레이팅하기 위하여 Windows로 포팅된 UNIX 기반 소프트웨어입니다. 그리고, MinGW은 Cygwin 1.3.3 버전에서 분리되어져서 나왔습니다.

그 이후 Cygwin과 MinGW은 완전히 다른 노선을 걷기 시작합니다. Cygwin은 Windows 위에서 작동하는 Linux 호환 Layer를 구성하고 그 위에서 추가 에뮬레이션되어 동작하도록 구현되었습니다. 하지만 MinGW는 네이티브(Native) Windows 타켓으로 동작하도록 구현되었습니다. 그러다보니 아무래도 MinGW가 Cygwin보다 성능면에서 더 빠르게 동작하는 경우가 많습니다. 대신 Linux 호환성 면에서는 Cygwin이 MigGW보다 더 안정적으로 작동합니다.

MinGW의 목표는 Windows에서 GNU 툴을 사용하기 위한 최소한의 환경 설정 제공에 있습니다. 그래서 이름도 MinGW(Minimalist GNU for Windows)입니다.


MinGW의 C++11 thread 지원 문제

MinGW에서 C++11의 thread를 정식으로 지원하지 않는 문제점이 있습니다. 덕분에 MinGW에서 Thread 관련 요소를 사용하려고 하면(특히 Mutex) 컴파일조차 되지 않고 에러가 발생합니다. 구글링을 통해서 알아보니 mingw-std-threads와 같은 라이브러리를 이용하면 해결할 수 있다고 하네요. 헤더 파일만 적당히 교체하면 되는 라이브러리라 큰 불편 없이 사용할 수 있을 것 같지만, 그래도 편법으로 해결하는거라 개운하지는 않네요. 그래서 저는 Cygwin을 추가로 설치했습니다. Cygwin에서는 이런 문제가 전혀 발생하지 않습니다.


MSYS

MSYS는 MinGW에서 bash나 make 등의 명령어를 수행할 수 있게 해주는 커맨드 쉘(Command Shell)입니다. Cygwin의 경우는 UNIX 대부분의 환경을 에뮬레이팅해주고 있지만, MSYS는 개발에 필요한 최소한의 요소들만 지원을 해주고 있습니다.

MSYS는 Cygwin의 초기 버전에서 분리되어 개발되었으며, 최근에는 Cygwin 최신 버전 기반으로 한 MSYS2도 있습니다. Cygwin이나 MSYS나 간단히 개발용으로 사용하기에는 큰 차이 없는 것 같습니다.


설치 용량 차이

대부분 하드디스크의 용량은 넉넉하다보니 설치 용량 차이가 큰 의미는 없을 수 있는데, 그래도 살짝 언급해봅니다. C++ 개발을 위한 MinGW의 설치 용량은 350MB 수준입니다. Cygwin의 경우는 약 10GB 수준입니다. 이것도 Cygwin 항목중에 development 항목만 추가했을 때의 용량입니다. 제가 C++ 개발을 위한 최소한의 옵션만으로 설정하지는 않았지만 그래도 아주 큰 차이가 있네요. 덕분에 설치 시간도 엄청나게 차이가 납니다. 물론, 설치는 처음 한 번만 하면 되니깐 아주 큰 문제는 아닐 수 있겠네요.

결국 C++11 thread 지원 문제 때문에 저는 MinGW를 설치했다가 지금은 완전히 지우고 Cygwin으로 넘어갔습니다.

find 사용법 - 파일 검색

|

리눅스에서 파일을 찾는 방법은 find 명령어를 이용해서 찾을 수 있습니다. 그리고 -name 옵션을 이용해서 원하는 파일을 검색할 수 있습니다.

탐색 경로를 생략한 경우에는 현재 작업중인 폴더부터 검색을 시작합니다. 읽기 권한이 없는 폴더는 건너뜁니다.

find -name [파일명]

ex)
find -name snowdeer

권한이 없는 폴더까지 검색을 하고 싶으면 앞에 sudo로 루트 권한을 얻으면 가능합니다.

루트 폴더부터 모든 폴더의 파일을 다 검색하고 싶을 때는 /를 명시하면 됩니다.

sudo find / -name snowdeer