반응형

CMake : 공식예제 step1 해보기


MS의 VS 시리즈 통합개발환경을 사용하다가 리눅스 같은 유닉스 계열에서 비통합개발환경에서 여러 소스파일을 컴파일을 할 경우 이를 도와주는 도구가 shell, makefile, CMake 등이 있다.

 소스파일이 많아지고 복잡해질 수록 shell 보다는 makefile, makefile보다는 CMake가 비교적 적합하다. 특히 CMake의 경우 윈도우에서도 빌드할 수 있기 때문에, 소스코드 생성시 의 운영체제의 고유 API를 사용하지 않았다면, 동일한 소스파일을 빌드할 수 있다. 이를 이용해서 OpenCV등 오래전 부터 지속된 오픈소스 프로젝트들이 CMake를 사용해서 사용되어져 왔다.


 문제는 이러한 강력한 기능이 있음에도 불구하고 튜토리얼 문서는 관리가 안되고 있는 듯하다. 이 글을 기록하는 시점에 3.5.1버전이 필자의 리눅스에 설치되어 있지만, 공식 홈페이지의 메인 튜토리얼에는 여전히 2.6 버전으로 되어 있다. 게다가 상당히 난잡하게 기록되어 있다. 아마도 이를 통해서 진입장벽을 만들고 싶었던건지 아니면, 기록이 귀찮았던건지는 물어보지 않아서 알 수 없다.


 일단은 예시 들을 진행을 해보면서, 발생되는 문제점을 해결하면서 기록을 하고자 한다.


CMake 개요

 cmake는 CMakeLists.txt 명으로 된 파일을 스크립트로 인식하여 makefile을 생성하여 최종적으로는 makefile(실행은 make)을 사용하여 실행 및 공유파일을 생성한다.




예시 소스코드


// tutorial.cxx

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"

int main(const int argc, const char * argv[])
{
    double inputValue;
    double outputValue;
    if(argc < 2)
    {
        fprintf(stdout, "usage: %s number\n", argv[0]);
        return 1;
    }
    inputValue = atof(argv[1]);
    outputValue = sqrt(inputValue);
    fprintf(stdout, "The square root of %g is %g\n",
        inputValue, outputValue);

    return 0;
}


 확장자가 cxx이지만 헤더파일을 살펴보면 c인것을 알 수 있다. "TutorialConfig.h"은 CMake에서 설정하는 파일로 빌드 직전에 생성된다.



예시 헤더파일


// TutorialConfig.h.in

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@


"@"로 감싼 부분은 CMake 파일에서 후에 정의 된 값이 들어가서 작성하게 된다.



예시 CMakeLists.txt


# CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(Tutorial)
# The version number
set(Tutorial_VERSION_MAJOR 1)
set(Tutorial_VERSION_MINOR 0)

# configure a header file to pass scma of the CMake settings
# to the source code
configure_file(
    "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
    "${PROJECT_BINARY_DIR}/Tutorialconfig.h"
)

# add the binary tree to the search path ofr include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")

# add the executedable
add_executable(Tutorial tutorial.cxx)


만약에 여기 까지 진행을 했는데, math.h에 관련된 에러가 발생한다면, 위의 마지막줄 add_executable() 직전에 한줄을 추가 해주자


# add link libraries
LINK_LIBRARIES(m)

주석에 표기 되어 있는대로 라이브러리를 추가 시켜준다. 원래는 cmake가 알아서 추가 시켜줘야 하는데, 간혹 안되는 경우가 있으니 참고 하도록 하자. 위의 한줄은 math.h를 include 했을 때 컴파일 과정중 링크 단계에서 -lm을 하는 것과 같은 효과가 있다.


CMake에서는 콤마(,)가 없다는 것을 주의 해야 한다.

project(Tutorial)은 이름 그대로 프로젝트 이름을 정의해준다.


 set() 키워드는 CMake내에서 변수를 정의 혹은 초기화를 해준다. set(Tutorial_VERSION_MAJOR 1)이라고 하면, Tutorial_VERSION_MAJOR이라는 변수 없다는 생성해서 초기화를 시킨다.


add_executeable(Tutorial tutorial.cxx)는 결과 파일이름이 Tutorial로 되고 여기에 포함되는 소스가 위에 열거가 된다. 예제에서는 하나의 소스파일이지만, 실제로는 여러개의 소스파일이 사용된다.


참조 자료

공식 튜토리얼(영문)

개발자 블로그



반응형

'각종 툴' 카테고리의 다른 글

[PyCharm]기본 키 맵 해제  (0) 2020.12.20
CMake 익히기 : 기초문법 (2)  (0) 2018.02.21
CMake 익히기 : 기초문법 (1)  (0) 2018.02.19
반응형

C에서 간단한 dll을 만들어 C++에서 사용하기


 C에서는 MVC++의 C++와 달리 "#pragma" 매크로를 지원하지 않는다. 하지만, C에서는 전통적으로 다른 파일에서 사용할 수 있도록 하는 "extern"을 키워드가 있다.


 다음은 MSDN의 간단한 예시를 조금 수정했다. 


내보내기 예시)

 MSDN의 예제의 경우 __declspec( dllexport )로 작성된 부분이 __declspec( dllimport )로 작성이 되어 있는데, MSDN측 오타로 생각된다.

// MyCFuncs.h
#ifdef __cplusplus
extern "C" {  // only need to export C interface if
                  // used by C++ source code
#endif

__declspec( dllexport ) void Hello(void);

#ifdef __cplusplus
}
#endif


// MyCFuncs.c
#include "MyCFuncs.h"
#include <stdio.h>

void Hello(void)
{
    puts("Hello world");
}


dll 들여오기(Import) 공통 작업

 C++의 dll 파일을 링크하는 것과 비슷한 준비 작업이 필요하다. 실행 프로그램의 프로젝트를 생성한다. 여기서는 "Windows 데스크탑"의 빈프로젝트로 생성한다.

해당 프로젝트 폴더로 내보내는 예시에서 만든 lib파일과 헤더파일을 복사한다.

"솔루션 탐색기"에서 "헤더 파일"항목에 마우스 우클릭을 한뒤 "추가 -> 기존항목"에서 복사한 헤더파일을 추가한다.



들여오기 예시1)

 "솔루션 탐색기"에서 해당 프로젝트 명을 우클릭하여 "프로젝트 속성" 창을 연다.

프로젝트 속성의 "링크 -> 일반"의 "추가 라이브러리 디렉터리" 항목에 lib 파일이 있는 폴더 경로를 추가 입력해준다.

프로젝트 속성의 "링크 -> 입력"의 "추가 종속성"항목에 lib파일 이름과 확장자 명을 추가 입력을 한다.

아래의 소스코드를 작성한다.

// MyCFuncsRef.cpp
#include "MyCFuncs.h"

int main(const int & argc, const char * argv[])
{
    Hello();
    return 0;
}


컴파일 후 프로그램을 실행할때에는 실행하는 폴더안에 해당 dll 파일이 반드시 있어야한다.



들여오기 예시2)

아래와 같이 매크로 "#pragma comment(lib, " ./MyCfuncs.lib")를 선언부 입력을 해준다.


// MyCFuncsRef.cpp
#pragma comment(lib, "./MyCFuncs.lib")

#include "MyCFuncs.h"

int main(const int & argc, const char * argv[])
{
    Hello();
    return 0;
}


컴파일 후 실행파일이 있는 폴더 안에 해당 dll 파일이 있어야 정상적으로 실행된다.



정리

 C의 경우 클래스와 같은 자료형을 지원하지 않기 때문에 단지 헤더파일 부분만 주의 깊게 작성하면 된다. 다만, C++에서는 해당 헤더파일이 C++에서 사용된다는 것을 알리기 위하여 매크로 변수 __cplusplus를 이용 하여 extern "c" { 항목을 활성 혹은 비활성 한다는 점을 기억하자.


 dll참조 함수의 성능을 높이기 위해 포인터로 함수 주소를 가져와서 호출하는 방법도 있는데, 이부분은 추가로 더 조사를 해봐야 될것 같다.



참고자료

MSDN C 함수를 ~ 내보내기




반응형
반응형

C++에서 간단한 dll를 만들어 C++에서 사용하기

 MS사에서 제공하는 MVC++ 컴파일러는 모던 C 표준 지원을 제대로 하지 않는다. 이러한 이유 때문인지 프로그래밍 입문 과목중에 C/C++이라는 과목이 존재하는 듯 하다.


 MVC++에서는 함수를 다른 프로그램에 사용할 수 있도록 내보내거나 들여오는 매크로를 지원한다. MSDN에서는 간단한 예시를 제공한다.


내보내기 예시)

우선 MathFuncsDll 이름의 프로젝트를 생성한다. 생성할때 dll프로젝트로 생성해야 하는데, VS 2017부터는 기존 마법사로 생설할 경우 "Visual C++" 하위의 "Windows 데스크톱" 항목의 Windows 데스크톱 마법사에서 생성하면된다. 마법사가 귀찮다면, DLL로 생성하면 된다. 

// MathFuncsDll.h

#ifdef MATHFUNCSDLL_EXPORTS
#define MATHFUNCSDLL_API __declspec(dllexport)
#else
#define MATHFUNCSDLL_API __declspec(dllimport)
#endif

namespace MathFuncs
{
    // This class is exported from the MathFuncsDll.dll
    class MyMathFuncs
    {
    public:
        // Return a + b
        static MATHFUNCSDLL_API double Add(double a, double b);

        // Return a - b
        static MATHFUNCSDLL_API double Subtract(double a, double b);

        // Return a * b
        static MATHFUNCSDLL_API double Multiply(double a, double b);

        // Return a / b
        // Throws const std::invalid-argument & if b is 0
        static MATHFUNCSDLL_API double Divide(double a, double b);
    };
}


위의 매크로 함수를 정의 하는데, dll프로젝트일 경우 컴파일러의 전처리 옵션에 [대문자 프로젝트 명] + "_EXPORTS"(여기서는 "MATHFUNCSDLL_EXPORTS")의 형태의 매크로가 자동으로 추가 되어 있다. 이러한 특징을 이용해서 헤더 파일에 DLL 프로젝트의 경우 내보내는 매크로 함수"__declspec(dllexport)"가 되고 그외 프로젝트에서는 가져오는 매크로 함수 "__declspec(dllimport)"로 치환이 된다.

 이렇게 만들어진 헤더 파일은 나중에 참조하는 실행 프로그램에서도 include 해야 한다.


// MathFuncsDll.cpp

#include <iostream>
#include "mathfuncsdll.h"

using namespace std;

namespace MathFuncs
{
    double MyMathFuncs::Add(double a, double b)
    { return a + b; }

    double MyMathFuncs::Subtract(double a, double b) 
    { return a - b; }

    double MyMathFuncs::Multiply(double a, double b)
    { return a * b; }

    double MyMathFuncs::Divide(double a, double b)
    {
        if(b == 0)
        {
            throw invallid_argument("b cannot be zero");
        }
        return a / b;
    }
}

 cpp 파일까지 작성하였다면 빌드를 하면 된다. 이때 "win32"로 했는지 "x64"으로 했는지 구분하는 것이 좋다. 에러가 없다면, 가능하면 Release로 빌드하여 최적화를 하자.



들여오기 사용 예시1)

 실행하는 프로젝트의 경우 선행 작업이 조금 필요하다. 우선 새로운 프로젝트를 만들자 이름은 대략 "MyExceRefDll"로 빈프로젝트로 만들어도 무난하다. 앞의 프로젝트에서 빌드한 파일중에 .lib와 dll 파일이 생성된 것을 알 수 있다. 빌드와 링크과정에는 헤더파일과 lib 파일이 필요하다. 헤더파일은 솔루션 탐색기에 추가를 시켜야 한다. "솔루션 탐색기 -> 헤더파일 -> 우클릭 -> 추가 -> 기존항목 -> 헤더파일"


// MyExecRefsDll.cpp

#include <iostream>
#include "MathFuncsDll.h"

using namespace std;

int main(void)
{
    double a = 7.4;
    int b = 99;

    cout << "a + b = " << MathFuncs::MyMathfuncs::Add(a, b) << endl;
    cout << "a - b = " << MathFuncs::MyMathfuncs::Subtract(a, b) << endl;
    cout << "a * b = " << MathFuncs::MyMathfuncs::Multiply(a, b) << endl;
    cout << "a / b = " << MathFuncs::MyMathfuncs::Divide(a, b) << endl;

    try
    {
        cout << "a / 0 = " << MathFuncs::MyMathFuncs::Divide(a, 0) << endl;
    }
    catch(const invalid_argument & e)
    {
        cout << "Caught exception: " << e.what() << endl;
    }

    return 0;
}

 lib파일은 "솔루션 탐색기 -> 프로젝트 -> 우클릭 -> 속성" 에서 "링커 -> 일반" 항목중 "추가 라이브러리 디렉토리"에 lib파일이 있는 경로를 추가 시킨다. 이후 "링커 -> 입력" 항목중 "추가 종속성"에 추가할 lib 파일명을 적어주면 된다. 이 예시에서는 "MathFuncsDll.lib"를 적어주면 된다.


 링크 옵션을 마치면, 컴파일을 한다. 이때 공부할때 습관적으로 F5키로 실행까지 하는데, 실행파일이 있는 폴더에 dll 파일(여기서는 "MathFuncsDll.dll")을 넣고 실행해야 한다. 별다른 오류 메시지 창이 안보이면, 잘 된거다.



들여오기 사용 예시2)

 앞의 예시는 MVC++ 컴파일러의 옵션 값을 넣어서 dll을 참조했다면, 이번에는 옵션 값을 수정하지 않고 참조 해보자. 앞의 예시와 동일하게 헤더파일을 솔루션 탐색기에서 인식할 수 있도록 추가 해야 한다.

 실행 프로그램의 소스 코드중에 MVC++에서 사용하느 매크로 함수 "#pragma comment()"를 사용하여 참조할 lib 파일의 경로와 파일명을 알려주면 된다. 그럼, 앞의 "예시1"의 컴파일 옵션을 컴파일러가 해당 소스를 읽을때 컴파일 옵션을 설정하기 때문에 따로 속성창을 열어서 수정하지 않아도 된다.


// MyExecrefsDll.cpp
// ...
#pragma comment(lib, "../../MathFuncsDll/Debug/MathFuncsDll.lib");
// ...



정리

 원리상 컴파일 옵션으로 작성이 되는 것이고 그 역할을 하는 매크로 함수를 컴파일러 수준에서 제공을 해주는 것을 이용하는 것이다. 이는 헤더파일이 없어도 참조함수를 선언해서 사용할 수 있지만, 복잡하고 많은 수의 함수를 일일히 선언해주는 것은 비 생산적인 일이 때문에 헤더파일은 그대로 사용하는데, 이 때문에 타사의 상용 라이브러리(흔히 dll)를 사용할 때 헤더파일은 대부분 같이 제공해준다.


 여기서는 간단하게 작성했지만, 가능하면 정신건강을 위해서 정리를 하는게 좋다. 들여오기 예시1, 2는 각각 장단점이 있으니 자신이 우선시 하거나 취향대로 사용하면 될 것 같다.


참조자료

MSDN VS2015(한글)

MSDN VS2015(영문)

DLL 작성 및 사용하기(한글 블로그)




반응형
반응형

윈도우즈 라이브러리 개념(LIB, DLL)


이글을 정리하게 된 경우 당연히 사용해야 할 상황이 닥쳤기(?) 때문에 적는다.


라이브러리 개념

 라이브러리는 일반적으로 운영체제에 많은 부분은 의지하는 경우가 있다. 따라서 리눅스와 윈도우의 라이브러리 확장자 이름이 다르다. 심지어 일부는 정의 하는 이름도 다르다.

 윈도우즈에서 개념적으로 정적 라이브러리와 동적 라이브러리로 분류가 되며, 각 확장자는 순서대로 lib, dll로 붙는다.


정적 라이브러리와 동적 라이브러리

 정적 라이브러리(Static Library)의 경우 종속적인(해당 라이브러리를 사용하는) 프로그램이 컴파일(빌드와 링크 포함)되는 시점에 필요로 하고 실행에는 이미 라이브러리의 내용이 포함되어 있기 때문에 정적 라이브러리 파일이 필요로 하지 않는다. 확장자는 .lib를 사용한다.

리눅스에서는 동일한 개념으로 확장자 .o(Object의 약자)를 사용한다.


 동적 라이브러리(Dybamic Library)는 종속적인 프로그램이 컴파일시 링크만 하게 된다. 이 때문에 실행 프로그램이 실행되는 시점에 동적 라이브러리 파일이 있어야 한다. 이 때 운영체제는 실행 프로그램에서 요청하는 dll 파일을 찾게 되는데, 첫째는 실행 프로그램의 같은 폴더내에서 찾게 되고, 그 다음은 하위 폴더, 마지막으로는 환경변수를 통해서 찾게 된다. 이러한 과정으로도 필요한 dll 파일을 찾지 못하게 되면, 오류 메시지를 보여주고 프로그램 실행이 중단된다.

리눅스에서는 비슷한(사실상 같은) 역할을 하는 라이브러리를 공유 라이브러리(Shared Library)라 부르고 확장자는 .so(Shared Object의 약자)를 사용한다.


정적 라이브러리 VS 동적 라이브러리

 vs는 실제 둘의 차이를 비교하기 위해서 많이 사용하는 검색 키워드이기도 하다. 두 방법이 각각 장단점이 있는데, 성능(흔시 실행 속도)는 정적 라이브러리가 앞서지만, 재사용성은 동적 라이브러리가 앞선다. 이는 동적 라이브러리를 많이 사용할 수록 여러 파일로 나누어져있기 때문에 발생하는 문제이기도 하다.


제작 및 사용 방법

 운영체제에 따라서 파일 확장자 부터 다르며, 제작 및 사용 방법도 컴파일의 종류에 영향을 받는다. 제작 및 사용 방법은 사용하는 컴파일러에 대해서 조사를 해야 한다. 다만, 대부분이 매크로와 컴파일러에서 제공하는 옵션 사용하기 때문에 원래 소스코드에 손을 덜 대거나 호환성이 높은 코드를 작성한다.



반응형
반응형

C# : const vs readonly

정리하게 된 배경

C++를 주로 사용하던 사람에게는 const라는 키워드가 상당히 익숙하다. 나중에 만들어진 C#은 당연히 기존의 관용적으로 사용되는 것을 보완 하는 방식으로 발전을 하게 되었다. 문제는 C#의 기본서를 통해서 readonly와 const의 차이점에 대한 설명이 부족하다. 때문에 이를 보완하기 위하여 기록한다.


const

 constant(일정한)의 앞글자 머리에서 따왔듯이 변하지 않는다는 의미로 사용된다. 하지만, 초기 컴퓨터는 대부분 수치를 다루다보니 키워드에 대해서 "상수"로 번역이 되어진것 같다. 하지만, 실제 의미는 원 단어에서 온것 처럼 변하지 않는 것을 의미한다(물론 그 것도 메모리상에서는 숫자에 불과하긴하다). 이때문에 선언시 초기화 된 값을 읽을 수 밖에 없다.


readonly

 C#에서 등장한 키워드로 직역만 해도 앞의 const와 동일하게 의미를 갖고 있다. 그럼 같은걸 뭐하로 const와 readonly 둘 다 사용하게 만들었을까? 가독성을 높이기 위해서 일까?

 사실 const와 readonly는 차이가 있다. const의 경우 말그대로 선언시 반드시 초기화를 해줘야 한다. 하지만, readonly는 선언시 반드시 초기화 할 필요가 없다. 하지만, readonly이지 않는가? 그렇다. 클래스의 맴버변수(혹은 필드)로 있을때 한번만 정의가 될 수 있다. 즉, 생성자로 클래스의 인스턴스가 생성될때 결정되고 변하지 않는 값을 사용할때 적절하다.

 물론 프로퍼티를 사용해도 같은 기능을 충분히 구현할 수 있다. 다만, 이러한 기능을 사용할지 않할지는 사용하는 개발자의 몫이다.




반응형
반응형

라즈비안 : Lite 버전 설치 및 초기 설정

알아야하는 이유

라즈베리 파이 뿐만 아니라 기존에 리눅스 계열의 서버나 제품을 만들 경우 흔히 개발중 혹은 학습과정에서 사용하는 GUI를 사용하지 않는다. 즉, 실제 배포 전단계에서는 Lite 버전으로 운영체제를 설치한 다음에 필요한 것만 설치 하여 운영을 한다. 이때문에 Lite 버전에서 환경을 설정하기 위한 기본적인 명령어는 알아야한다.


라즈비안Lite 다운로드

라즈베리파이 공식 웹페이지에서 다운로드 받을 수 있다. 또한 토렌트를 통해서 다운로드 받을 수도 있다. 토렌트 시드 파일을 받아서 다운로드 하면 된다.

링크

초기 설치 후 로그인 계정과 패스워드를 묻는데, 초기 기본정보는 pi/raspberry 인데, 보안상 적어도 패스워드는 반드시 바꾸도록 하자.


환경설정

sudo raspi-config



 초기 라즈비안 버전에서는 여기서 ssd의 저장공간을 확장했지만, 요즘에는 처음 실행시 자동으로 확장을 해준다. 여기서 보여지는 환경설정에서 Camera, ssh, p2c, serial port 등나 각종 센서에 필요한 인터페이스를 활성화해줘야 사용 가능하다.

 만약 Wifi를 사용해야 한다면, 국가를 US로 해줘야 한다. 이는 기존에 버그로 인해 공유기 인식이 안되서 해주는 것인데, 만약 해당 버그가 수정되었다면, 바꿔줄 필요가 없다.



반응형
반응형

배경

자주 사용하는데 문제는 유닉스 환경을 잠시 안쓰면 잊어서 기록을 함. 더 자세한 내용은 "man tar"에서 볼 수 있지만, 귀찮으니 자주 쓰는 건 외우도록 하자.

일일히 이해하고 사용하기 귀찮다면 관례적으로 압축은 -cvzf, 해제는 -xvzf 로 외워도 쓰는데는 지장없다.

개요

압축 파일의 본질은 말그대로 알고리즘으로 파일의 크기를 줄이는 데에 있다. 하지만, 그외에 더 좋은 용도로 사용된 것이 바로 여러 파일들을 하나로 합치는 것들이다. tar는 기본적으로 여러 파일을 하나라 합치나 압축을 하는 기능이 없다. 때문에 tar 뒤에 gz 같은 추가 확장자로 추가로 압축 작업을 했는지 구분하기도 한다.

옵션

x 묶음 해제
c 파일 묶음
v 묶음/해제 과정을 화면에 표시
z gunzip 을 사용
f 파일 이름을 지정
p 권한(permission)이 원본과 동일하게 유지

 

압축

와일드 카드"*" 사용가능함. 

예시)

tar -cvzf {생성할 파일명}.tar.gz {압축할 파일 및 폴더}

압축 해제

예시)

tar -xvzf {압축된 파일명}.tar.gz

참고자료

http://sarghis.com/blog/468/

반응형

'리눅스 > 리눅스 공통' 카테고리의 다른 글

리눅스 공통 : ssh로 원격 명령어 실행  (1) 2017.09.03
반응형

C# 싱글톤 패턴 상속용 클래스

알게된 배경

싱글톤 패턴은 비교적 자주 사용되는 패턴이고, 멀티 스레드 프로그램을 작성할 경우 서로 상성이 안좋기 때문에 크리티컬 섹션에 대해서 뮤텍스(C#에서는 락)을 잡아줘야 한다. 문제는 이러한 패턴은 매번 반복이 되기 때문에 부모 클래스로서 작성을 해놓고, 상속받아서 기능을 구현하는 것이 여러모로 편리하다고 생각이 들기 때문에 찾아보니 해당 패턴이 있었다.

 그래서 메모겸 샘플 코드를 남긴다


부모 싱글톤

예시)

namespace Single
{
    public class Singleton<T> where T : class, new()
    {
        protected static object _instanceLock = new object();
        protected static volatile T _instance;
        public static T Instance
        {
            get
            {
                lock(_instanceLock)
                {
                    if(null == _instance)
                         _instance = new T();
                }
                return _instance;
            }
        }

    }
}



자식 싱글톤

예시)

namespace Single
{
    class MyClass : Singleton<MyClass>
    {
        // contents
        public void Print()
        {
            Console.WriteLine("Hello Singleton?");
        }
    }
}



참고자료



반응형

'C#' 카테고리의 다른 글

C# : 닷넷에서 Broadcast UDP를 보내기(1)  (0) 2018.01.29
C# : const vs readonly  (0) 2017.10.25
C# 싱글톤 패턴 : 동적 싱글톤  (0) 2017.09.04
C# Socket : 고정 구조체 만들기  (0) 2017.07.11
C# WinForm : 문자 픽셀 측정  (0) 2017.07.06
반응형

C# 싱글톤 패턴 : 동적 싱글톤

사용 목적

 하나만 있어야 하는 경우 사용되는 패턴이다. 보통 매니져 형태로 사용되는 경우에 사용된다. 간단하면서 의외로 자주 사용되는 패턴이기도 하다.

 하지만 최근에 멀티 쓰래딩을 구현할 경우 주의가 필요한 패턴이다. 보통 뮤텍스(크리티컬 섹션)와 같은 lock 기능을 통해서 동시에 접근하는 것을 막기도 하는데, 이런일이 잦을 수록 성능 향상을 저해 한다는 점도 있다.


싱글톤을 위한 기본 상식

 싱글톤(Singleton)이라는 단어에서 알 수 있듯이 하나만 존재하는 객체를 의미한다. 그래서 클래스라는 틀로 찍힌 인스턴스(실제 객체)는 하나만 존재 해야 한다.


 이 처럼 하나만 갖게 되어야 하는 조건을 충족 시키기 위해서 다음 조건들을 충족 해야 한다

 1. 생성자를 외부에서 접근되어서는 안된다(하나만 있어야 하기 때문)

 2. 인스턴스(실제 객체)는 하나만 있어야 한다.


 특히 1번의 조건을 충족하기 위해서 대부분 클래스를 지원하는 언어에서는 생성자를 private 혹은 protected 로 정의하여 외부에서 접근을 못하도록 막는 패턴을 갖게 된다.

 2번의 조건을 충족시키기 위해서는 내부에 인스턴스를 갖고 있되 접근이 가능하도록 해야 한다. 따라서 이를 위해 static으로 선언을 하게 된다. 이렇게 선언된 변수 혹은 객체는 해당 클래스를 통해서만 접근이 가능하게 된다. 그와 동시에 글로벌 영역에 객체가 존재하게 된다.

 그리고 마지막으로 싱글톤을 사용할 수 있도록 Instance 메서드를 만든다. C++의 경우 GetInstance()로 선언하는것이 관용적이지만, C#에서는 프로퍼티 기능이 있기 때문에 Get 관용구를 생략하는 경우가 있다.


구현 방법

동적 싱글톤 패턴 이기 때문에 인스턴스를 요청할때 없는 경우 생성해서 인스턴스를 반환하게 구현하면 된다.

예시)

using System;
public class Singleton
{
    private static Singleton _instance;
    private Singleton() {}
    public static Singleton Instance
    {
        get
        {
            if(_instance == null)
            {
                _instance = new Singleton();
            }
            return _instance;
        }
    }
}




위는 정석적인 방법이고 편의상 ? 연산을 이용하여 한줄로 선언할 수 있다. 이러한 방법은 코드를 간결하게 하지만, lock을 이용한 크리티컬 섹션을 설정할 수 없는 단점이 있다.

예시)

using System;
public class Singleton
{
    private static Singleton _instance;
    private Singleton() {}
    public static Singleton Instance
    {
        get
        {
            return (null == _instance) ? _instance = new Singleton() : _instance;
        }
    }
}




참조 자료

MSDN 싱글톤 패턴 문서



반응형
반응형

리눅스 공통 : ssh로 원격 명령어 실행

알게 된 배경

 서적을 통해서 쉘 스크립트를 통해서 파일 업로드 혹은 다운로드가 가능하다는 것을 알게 되었다. 특히 scp와 private와 public 키를 조합을 하여 자동 백업 등 여러 작업을 할 수 있다. 하지만, 종종 원격 디바이스(리눅스로 된)에 업로드된 파일등을 실행을 해야 할 경우에는 이러한 방법을 사용해야 한다.


 특히 다수의 서버에 프로그램을 테스트 할 경우에 이러한 방법을 적용할 수 있다면, 쉘 스크립트로 작성하여 자동화하는 것이 가능하게 된다.


명령어 전달 방법

방법은 의외로 간단하다 ssh 접속 방법에서 뒤에 명령어를 입력을 해주면 된다.


# 만약 rami 계정으로 192.168.0.2에 ls를 입력할 경우
ssh rami@192.168.0.2 ls



만약 명령어 이외에 옵션값도 전달을 해야한다면, ''이나 ""으로 명령어를 감싸면 된다.


# 만약 -al 옵션을 추가로 넣어야 할 경우
ssh rami@192.168.0.2 "ls -al"



 이제는 일괄로 ssh를 통해 명령어를 전달을 해야 한다면, 스크립트를 작성해서 진행하도록 하자.

 여기서 내 목적은 일괄적으로 각 서버에서 업로드한 프로그램의 make 명령어를 실행하는 것이었는데, make라는 명령어는 해당 폴더에 존재하는 파일명이 아니기 때문에 스크립트로 작성해서 실행하도록 했다. 일단 해결을 했지만, 더 좋은 방법이 있을 것 같다.



참조자료

해외 블로그

반응형

'리눅스 > 리눅스 공통' 카테고리의 다른 글

유닉스 : tar.gz 압축/해제 명령어  (0) 2017.09.29

+ Recent posts