반응형

OS: Ubuntu 14.04 LTS (amd64)


우분투(Ubuntu)에서 그냥 apt-get install로 gradle을 설치했더니 1.4가 설치되었다.


그런데 Spring REST 서버 코드를 빌드하는 과정에서 에러가 발생했는데 살펴보니 gradle-2.9 이상을 쓰라는 것이었다.


사실 그냥 gradle 공식 사이트 [1]에서 직접 받아서 설치해도 문제는 없다.

하지만 apt-get을 통해서 높은 버전 (또는 비교적 최신 버전)을 설치하고 싶을 경우에는 ppa를 통해 최신 gradle을 받을 수있는 repository를 등록해서 해결할 수 있다. [1]


$ sudo add-apt-repository ppa:cwchien/gradle

$ sudo apt-get update


$ sudo apt-get install gradle-3 <-- 여기까지 입력하고 탭(Tab) 키를 연타해서 설치할 수 있는 버전을 찾아서 설치하면 된다.




<참고자료>

[1] https://gradle.org/gradle-download/

[2] Upgrading Gradle to the latest version on Ubuntu, http://wtanaka.com/node/8079

반응형
블로그 이미지

Bryan_

,
반응형

OS: Ubuntu 14.04 (amd64)

g++ version: 4.8.4

Eclipse: Mars, Neon



이클립스(Eclipse)에서 C++2011  문법(std::thread나 향상된 for loop 같은 것)을 쓰려고 하면 빌드 설정에 -std=c++0x 또는 -std=c++11 같은 플래그를 추가해 두어도 정작 에디터에서 계속 syntax error를 표시하는 경우가 있다.


(이클립스 에디터가 C++11 문법에 따라 쓴 std::thread 코드를 

unresolved symbol error로 표시하고 있다.)



해결하려면, 프로젝트 이름에 마우스 오른쪽 단추를 누르고 Properties로 가서,

C/C++ General > Preprocessor Include Paths, Macros etc.로 간 다음,

Providers 탭에서 CDT GCC Build-in Compiler Settings를 선택한다.


그리고 하단에 "Use global provider shared between projects" 선택을 해제하고,

Command to get compiler specs 칸에 -std=c++0x 를 추가한다.


또한 순서상 중간 쯤에 와 있는 CDT GCC Build-in Compiler Settings 항목을 Move Up을 이용해서 가장 위로 끌어올린 뒤에 Apply 버튼과 OK 버튼을 누른다.




마지막으로, 이클립스 메뉴에서 

Project > C/C++ Index > Re-resolve Unresolved Includes

Project > C/C++ Index > Freshen All Files

Project > C/C++ Index > Rebuild

를 차례대로 눌러 주면 에러로 표시하지 않게 된다.


(C++ 2011 문법의 syntax error가 해결된 이후의 에디터 화면)




<참고자료>

[1] http://stackoverflow.com/questions/17457069/enabling-c11-in-eclipse-juno-kepler-luna-cdt



반응형
블로그 이미지

Bryan_

,
반응형

OS: Ubuntu 14.04 (amd64)

g++ version: 4.8.4



C++11에 정의되어 있는 thread를 코드에 사용해서 이클립스에서든 Makefile을 직접 써서든 그냥 빌드하면 컴파일 에러가 나는데, 이 때는 -std=c++11 플래그를 추가하라고 나와 있다. [5]

다만 쓰려는 코드가 또 쓰레드이기 때문에 -pthread도 추가하도록 되어 있다.


하지만 위와 같은 플래그를 추가하고 나서도 실행 단계에서 아래와 같은 에러가 나면서 실행이 중단된다.


terminate called after throwing an instance of 'std::system_error'

  what(): Enable multithreading to use std::thread: Operation not permitted


StackOverflow [1, 2]를 보면 gcc의 버그라는 게 결론이고, gcc 패키지에도 버그로 보고되어 있다 [3]. 


해결책으로 특정 flag를 추가해 줘야 한다고 나와 있다.

기본적으로 -Wl,--no-as-needed 를 추가해 주면 된다고 한다.


그런데 내 경우에는 g++ 4.8.4를 쓰고 있어서 flag 하나를 더 추가해 줘야 한다는 댓글이 있어서 최종적으로 -std=c++11 -pthread -lpthread -Wl,--no-as-needed 이렇게 추가를 했더니 빌드와 실행 모두 잘 되었다.


Eclipse CDT에서 설정하는 방법은 [4]에 설명되어 있다. Project Properties에서 C/C++ Build 부분은 빌드할 때 옵션이고, C/C++ General 쪽에 해주는 설정은 아마 에디터에서 보여지는 문법상의 에러를 표시할 때 필요한 것 같은데, 이상하게 에디터 쪽에서는 잘 적용이 되지 않는 것 같았다.




<참고자료>

[1] http://stackoverflow.com/questions/19463602/compiling-multithread-code-with-g

[2] http://chat.stackoverflow.com/transcript/message/12447014#12447014

[3] https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/1228201

[4] http://wiki.eclipse.org/CDT/User/FAQ#CDT_does_not_recognize_C.2B.2B11_features

[5] http://stackoverflow.com/questions/9131763/eclipse-cdt-c11-c0x-support



반응형
블로그 이미지

Bryan_

,
반응형

자바(Java)에서 Exception을 잘 다루면 여러 상황에 대한 대응력과 유연성을 높일 수 있지만, 예외처리에 대한 일관된 기준이나 잘 정리된 설계가 없으면 어떻게 처리(handling)할 지 막막해지기도 한다. 그래도 코딩하는 과정에서, 내가 만든 특정한 클래스를 참조해서 쓰는 다른 (작성자가 나일 수도 있고, 다른 개발자일 수도 있는) 클래스에게 이 예외상황만큼은 반드시 명시적으로 인지하고 특별하게 처리하도록 하고 싶으면 메쏘드 제목에서 throws 구문으로 예외를 caller에게 전달해야 한다.


그런데 특정한 예외를 caller에게 전달하려고 throws로 예외를 명시했는데도 caller 쪽에서 그 예외를 catch하지 못하는 경우가 있는데, 알고 보니 throw 하는 예외가 상속 관계에 의해서 부모 예외 타입으로 다른 곳에서 먼저 catch되는 바람에 caller 쪽에서 처리하지 못했던 것이었다.



구체적인 상황은 다음과 같다:


UDP Datagram Socket을 이용한 메세지 송수신 역할을 담당하는 클래스가 있는데, 여기에 타임아웃(timeout) 기능을 추가해서 특정한 메세지 전송에 대해서 응답을 받기 위해서 UDP Socket을 열되, 일정 시간 동안만 기다리도록 만들 필요가 생겼다. 찾아보니 Socket 클래스의 setSoTimeout 메쏘드를 시간값 파라미터와 함께 호출하면 해당 시간이 지난 뒤에 자동으로 SocketTimeoutException을 발생시킨다는 사실을 확인했다. 


그래서 아래와 같이 sendMessageAndGetReply(String ip, int port, String msg, int timeout) 메쏘드를 정의하고 throws SocketTimeoutException을 추가로 적어 주었는데, 그럼에도 불구하고 caller 쪽에서는 SocketTimeoutException을 catch할 수가 없었다.



public static String sendMessageAndGetReply(String ip, int port, String msg, int timeout) throws SocketTimeoutException {

String reply = null;

byte[] sendData = new byte[1024];

byte[] receiveData = new byte[1024];

try {

DatagramSocket clientSocket = new DatagramSocket();

sendData = msg.getBytes();

DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName(ip), port);

clientSocket.send(sendPacket);

DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length);

clientSocket.setSoTimeout(timeout); // 추가로 타임아웃을 명시적으로 설정한 부분

clientSocket.receive(recvPacket);

reply = new String(recvPacket.getData());

clientSocket.close();

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

return reply;

}



그런데 신기하게도 실행 화면에서는 SocketTimeoutException이 발생했다고 출력은 되는데, 정작 caller에서의 catch 구문은 실행되지 않았다.

코드의 다른 곳에서 해당 예외를 이미 처리했다는 의미인데, 알고 보니 sendMessageAndGetReply 메쏘드에서 catch (IOException e) 부분이 원인이었다. SocketTimeoutException은 java.io.InterruptedIOException을 extend한 자식 클래스이고, InterruptedIOException은 또한 IOException을 extend하고 있기 때문에, sendMessageAndGetReply가 해당 예외를 이미 처리해 버렸기 때문에, 제아무리 메쏘드 이름 옆에 throws로 명시해 두어도 throw가 되지 않았던 것이었다.


이것을 해결하기 위해서 결국 코드를 아래와 같이 고쳐야 했다. [2]


public static String sendMessageAndGetReply(String ip, int port, String msg, int timeout) throws SocketTimeoutException {

String reply = null;

byte[] sendData = new byte[1024];

byte[] receiveData = new byte[1024];

try {

DatagramSocket clientSocket = new DatagramSocket();

sendData = msg.getBytes();

DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName(ip), port);

clientSocket.send(sendPacket);

DatagramPacket recvPacket = new DatagramPacket(receiveData, receiveData.length);

clientSocket.setSoTimeout(timeout); // 추가로 타임아웃을 명시적으로 설정한 부분

clientSocket.receive(recvPacket);

reply = new String(recvPacket.getData());

clientSocket.close();

} catch (UnknownHostException e) {

e.printStackTrace();

} catch (IOException e) {

if(e instanceof SocketTimeoutException){

// 자식 클래스 예외를 특별하게 처리

throw new SocketTimeoutException();

}

e.printStackTrace();

}

return reply;

}


이렇게 했더니 콜 스택이 짧아지긴 했지만, 그래도 caller 쪽으로 Socket TimeoutException만큼은 확실하게 넘어가는 것을 확인할 수 있었다.


결론적으로, 당연한 얘기지만 예외를 처리할 때, throw하려는 예외가 혹시 해당 위치에 이미 존재하는 다른 catch 구문에 의해서 같이 처리되지는 않는지 상속 관계를 바탕으로 꼼꼼하게 확인할 필요가 있다.




<참고자료>

[1] http://stackoverflow.com/questions/27797451/i-cant-catch-sockettimeoutexception

[2] http://stackoverflow.com/questions/20532855/why-cant-i-handle-exception-e-with-try-catch-clause



반응형
블로그 이미지

Bryan_

,
반응형
연구 코딩할 때마다 느끼는 점은, 왠지 나만 그런 것 같기도 하지만 ㅠㅠ 적합한 데이터 구조를 선택하는 것이 생각만큼 간단하지 않다는 것이다. 아니 좀더 정확하게 표현하면, 무엇이 적합한 데이터 구조인지는 뻔하지만, 그 구조가 어디서 어떻게 쓰일지를 미리 다 예측할 수 없어서 고민이다.

처음부터 몇 수 앞을 내다보고, 내가 구현한 실험환경이 어디까지 확장될 것인지를 염두에 둬서 요구사항 분석을 한다면 시행착오가 줄어들겠지만, 당장 실험결과를 빨리 그래프로 찍어내야 하는 마당에 장인정신(?)으로 이런 올라운드 플레이어 같은 제품을 천천히 제작할 수는 없는 노릇이다.

중간결론으로 얻은 것은... 결국 내 입장에서는 너무 지나치게 이런 선택의 문제가 조심스러워서 생각만 하느라 시간을 많이 허비한다는 것이다. 일단 방향이 아예 잘못되지 않았다면, 즉 통째로 뜯어고칠 위험을 최대한 줄였다면, 재빨리 구현해서 비효율적이더라도 돌아가는 코드를 먼저 얻는 것이 필요한 것 같다. 그 다음에 계속 고칠 것들은 버전업 한다는 생각으로 고쳐야 할 것 같다.

예를 들면 이렇다:

네트워크로 연결된 이웃노드의 실시간 상태정보를 저장하는 간단한 테이블 구조가 필요해서 처음에 ArrayList로 무작정 시작했다가, 중간쯤 구현해서 생각해 보니 무진장 자주 테이블 검색을 해야 되는데 그 때마다 O(N)의 검색시간을 소비하면 낭비일 것 같아서 O(1)로 줄어드는 Hashtable로 바꿨다.
그렇게 구현을 하다가, 이 테이블의 값을 실시간으로 로그 파일에 저장시키야 하는 요구사항이 추가되었다. 테이블은 매번 최신 값만 저장하고 있기 때문에 매 시간마다 테이블의 값들을 로그 파일에 한 줄씩 추가로 기록해야 하는데, 이 때 테이블에 항목이 추가된 시간 순서를 유지해야 한다.
처음에는 Hashtable에서 values() 메쏘드로 값들만 통째로 얻어 와서 나열하면 될 줄 알았는데, 생각해 보니 해쉬값에 따라 제멋대로 정렬돼서 나오기 때문에 시간 순서를 유지하지 않는 것에 잠시 멘붕...
결국 시간 순서대로 입력되는 새로운 키 값을 순서대로 저장하는 ArrayList를 하나 더 유지하고, 이걸 기준으로 Hashtable을 다시 탐색해서 파일에 기록하기로 했다.

문제는 위와 같은 테이블 구조가 한개만 있는 것이 아니라서 각 테이블 구조에 다 시간 순서의 ArrayList를 추가해야 되는 것...

처음부터 시간 순서대로 추가되는 키의 ArrayList와 Hashtable을 쌍으로 관리하도록 설계를 하고 이것을 상속받아서 다른 모든 테이블들을 구현했으면 좋았겠지만, 그러면 아직도 돌아가는 코드를 못 봤을지도 모르겠다.


마치 알파고가 바둑 게임에서 다음 수를 선택할 때, 계산할 시간이 충분한 경우와 제한적일 경우에 최적의 선택이 미묘하게 달라지는 것처럼 어쩌면 나도 경험이 부족하고 생각할 시간도 제한적인 상황에서 최선의 코딩 방향을 선택하는 것에 어쩔 수 없이 차이가 있음을 인정해야 할 것 같다.

이렇게 배워 가면서 점차 더 빠른 시간 안에 더 효율적으로 돌아가는 프로그램을 개발할 수 있게 되겠지. 꾸준히 연습하자.

반응형
블로그 이미지

Bryan_

,