Tumgik
coldmund · 4 years
Text
Micro service architecture
Now I regrect why I have forgotten that there's no Silver bullet. We cannot keep transaction safe and Saga pattern seems to be another B.S.
I wanna go back to Monolithic heaven.
15 notes · View notes
coldmund · 4 years
Text
Theia
I have waited for vscode team to make the outline window detachable, but it seems that it's rather challenging than I expected. Then I found Theia.
It have almost same look with vscode but outline window is on the right side.
below is my test setting(package.json)
{ "private": true, "dependencies": { "@theia/callhierarchy": "next", "@theia/file-search": "next", "@theia/git": "next", "@theia/json": "next", "@theia/markers": "next", "@theia/messages": "next", "@theia/mini-browser": "next", "@theia/navigator": "next", "@theia/outline-view": "next", "@theia/plugin-ext-vscode": "next", "@theia/preferences": "next", "@theia/preview": "next", "@theia/search-in-workspace": "next", "@theia/terminal": "next", "@theia/debug": "next" }, "devDependencies": { "@theia/cli": "next" }, "scripts": { "prepare": "yarn run clean && yarn build && yarn run download:plugins", "clean": "theia clean", "build": "theia build --mode development", "start": "theia start --plugins=local-dir:plugins", "download:plugins": "theia download:plugins" }, "theiaPluginsDir": "plugins", "theiaPlugins": { "vscode-builtin-node-debug2": "http://open-vsx.org/api/ms-vscode/node-debug2/1.33.0/file/ms-vscode.node-debug2-1.33.0.vsix", "vscode-builtin-python": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/python-1.39.1-prel.vsix", "vscode-builtin-java": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/java-1.39.1-prel.vsix", "vscode-builtin-sql": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/sql-1.39.1-prel.vsix", "vscode-builtin-bat": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/bat-1.39.1-prel.vsix", "vscode-builtin-cpp": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/cpp-1.39.1-prel.vsix", "vscode-builtin-css": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/css-1.39.1-prel.vsix", "vscode-builtin-html": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/html-1.39.1-prel.vsix", "vscode-builtin-javascript": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/javascript-1.39.1-prel.vsix", "vscode-builtin-json": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/json-1.39.1-prel.vsix", "vscode-builtin-markdown": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/markdown-1.39.1-prel.vsix", "vscode-builtin-npm": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/npm-1.39.1-prel.vsix", "vscode-builtin-scss": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/scss-1.39.1-prel.vsix", "vscode-builtin-typescript": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/typescript-1.39.1-prel.vsix", "vscode-builtin-typescript-language-features": "https://github.com/theia-ide/vscode-builtin-extensions/releases/download/v1.39.1-prel/typescript-language-features-1.39.1-prel.vsix" } }
and launch.json sample to debug node.js code.
{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. "version": "0.2.0", "configurations": [ { "type": "node2", "request": "attach", "name": "Attach by Process ID", "processId": "${command:PickProcess}", "skipFiles": [ "/**" ] }, { "type": "node2", "request": "launch", "name": "Launch Program", "skipFiles": [ "/**" ], "program": "${workspaceFolder}\\test1\\test.js" } ] }
if you want to attch debugger to running process, run the code from theia terminal with --inspect option.
4 notes · View notes
coldmund · 5 years
Text
URI encoding
image file upload 후 꺼내서 화면에 표시해야하는데, 400 error 발생
1 tomcat 7에서는 문제 없는데, tomcat 8만 발생하며 해당 파일은 브라우저에서 URL입력해도 읽어오지 못함.
2 이미지 파일 업로드 시 파일명에 날짜를 추가하는데 앞뒤로 "[]"를 추가하며 발생한 문제. 원래 해당 character는 URL에 사용하면 안됨. (https://tomcat.apache.org/tomcat-8.5-doc/config/http.html)
3 파일명을 URLEncoder.encode(..., "UTF-8) 로 변경하면 동작.
4 code 수정 없이 server.xml의 connector tag에 relaxedQueryChars option 추가하는 방법이 있다고 하나 테스트 결과 실패. (https://stackoverflow.com/questions/50361171/how-to-allow-character-in-urls-for-tomcat-8-5)
1 note · View note
coldmund · 5 years
Text
JRE of Java 9 and later
- Oracle의 JDK license 정책이 변경되서 OpenJDK로 변경하려다가 이왕이면 Java version을 올리면 어떨까 싶어 OpenJDK 11을 설치 - 설치하고보니 JRE가 없어 Tomcat + Spring MVC로 개발한 application의 배포를 어찌할까 고민하게 됨. - Java 9부터 Oracle에서 JRE는 배포하지 않으며 필요한 실행환경을 직접 만들어 배포하도록 함. 그 이유는, - JRE의 크기가 점점 커지고, - Java 9부터 module을 지원. - 이미 만들어진 jar 파일에 대해서는 `jdeps --list-deps <jar file>`로 dependency를 check 후 `jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules <modules-comma-seperated> --output <path>`로 실행환경 제작. - 참고: https://medium.com/azulsystems/using-jlink-to-build-java-runtimes-for-non-modular-applications-9568c5e70ef4 - 전체 실행환경을 만들기 위해서는 `jlink --no-header-files --no-man-pages --compress=2 --add-modules $($(java --list-modules) -join "," -replace "@[0-9]*") --output jre-11` 실행. - 참고: https://stackoverflow.com/questions/51403071/create-jre-from-openjdk-windows
7 notes · View notes
coldmund · 6 years
Text
JPA, OrderBy with findAll
JPA를 이용해 find...()할 경우 OrderBy를 이용해서 sorting 가능.
public ??? findBySoundCategoryOrderByIndexAsc(Integer soundCategory);
하지만, findAll()은 OrderBy 를 그대로 사용할 수 없다.
public ??? findAllOrderByIndexAsc(Integer soundCategory); // ERROR public ??? findAllByOrderByIndexAsc(Integer soundCategory); // findAll 다음에 ‘By’ 추가
2 notes · View notes
coldmund · 6 years
Text
java exception
Exception은 try-catch 필수, RuntimeException은 안해도 됨.
multicatch 블럭의 exception object
걸려있는 모든 excpetion의 조상 class의 method만 사용 가능.
값을 변경할 수 없음.
finally는 try나 catch 블럭에 return이 있어도 실행됨. return type이 void가 아닌 경우 try, catch가 아닌 finally의 값이 return됨. return 문에서 side-effect가 발생하는 경우라면?
try-with-resource -JDK1.7 이후
try { fis = new FileInputStream("score.dat"); dis =- new DataInputStream(fis); ... } catch(IOException ie) { ie.printStackTrace(); } finally { try { if(dis != null) dis.close(); } catch(IOException ie) { ie.printStackTrace(); } }
아래와 같이 변경 가능.
try(FileInputStream fis = new FileInputStream("score.data"); DataInputStream dis = new DataInputStream(fis)) { ... } catch(IOException ie) { ie.printStackTrace(); }
try 블럭을 벗어나면서 close()가 호출되고 이후 catch 블럭이나 finally 블럭이 수행됨.
try 블럭 안에 변수 선언 가능.
자동으로 close()가 호출되려면 AutoCloseable interface를 구현해야 함. try 블럭에서 exception 발생 후 close()에서 exception이 또 발생할 경우 후자는 supress됨.
연결된 exception
exception 발생 시 catch 블럭에서 해당 exception을 새로운 exception에 initCause()로 저장 후 새로운 exception을 throw.
여러가지 exception을 상속관계 없이 하나의 exception으로 처리 가능.
checked exception을 unchecked exception으로 변경 가능.
1 note · View note
coldmund · 6 years
Text
debug for spring novice about jdbc-mariadb.. or something else.
팔자에도 없던 spring project를 위해 https://www.inflearn.com/course/%ec%9e%90%eb%b0%94-%ec%8a%a4%ed%94%84%eb%a7%81-%ea%b0%95%ec%a2%8c/ 에서 spring 강좌 수강하던 중, '21강 JDBC'에서 실습이 막힘. 그 전까지는 oracle로 된 실습 코드를 maria DB에 맞춰 어찌어찌 해왔는데...
일단 pom.xml에 아래 내용 추가
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.18.RELEASE</version> </dependency>
이렇게 해도 "Error: BeanDefinitionStoreException failed to read candidate component class" error 발생. 검색해보니 https://www.javagists.com/beandefinitionstoreexception-failed-to-read-candidate-component-class 와 몇군데에서 spring과 java version이 맞아야 한다고 나옴. 설치된 jdk는 1.8이었고 이 버전은 spring 4.x를 사용해야한다고 하는데, pom.xml에는 spring 3.1로 되어있음. 그리고 pom.xml의 java version은 1.6임. 무슨 경우인지???
일단 pom.xml의 java version 1.8로 바꾸고 https://www.sity.kr/yc5/bbs/board.php?bo_table=webinfo&wr_id=56 참고해서 spring version을 4.3.4.RELEASE로 변경. 그리고 관계있는지 모르겠지만 jsp-api 2.2로 바꿈. servlet-api는 3.0으로 바꾸면 동작 안함.
여기까지하면 돌아가기는 하는데, STS의 problems에 java version 관련 오류 뜸. project facets에서 java version 1.8로 변경.
2 notes · View notes
coldmund · 7 years
Text
how to iterate a vector
std::vector<>를 iterate할 때 어떤 방법이 더 빠를까?
#include <vector> #include <iostream> #include <chrono> #include <random> #include <ctime> #include <algorithm> #define VECTOR_SIZE 10000000 int main() { volatile double sum; std::vector v(VECTOR_SIZE); unsigned seed1 = std::chrono::system_clock::now().time_since_epoch().count(); std::mt19937 g(seed1); std::for_each(v.begin(), v.end(), [&g](double &d) { d = g(); }); sum = 0; auto t1 = std::chrono::system_clock::now(); std::for_each(v.begin(), v.end(), [&sum](double d) { sum += d; }); auto t2 = std::chrono::system_clock::now(); auto diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; sum = 0; t1 = std::chrono::system_clock::now(); for(double d : v) sum += d; t2 = std::chrono::system_clock::now(); diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; sum = 0; t1 = std::chrono::system_clock::now(); for(auto it = v.begin(); it != v.end(); ++it) sum += *it; t2 = std::chrono::system_clock::now(); diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; sum = 0; t1 = std::chrono::system_clock::now(); for(int i=0; i<VECTOR_SIZE; ++i) sum += v[i]; t2 = std::chrono::system_clock::now(); diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; return 0; }
환경: CTO cloud, ubuntu 14, 16 core, ...
compile: g++ -std=c++11 -O0 main.cpp
결과
for_each: 106.046 range-based for: 86.0454 iterator: 146.815 for: 52.5619
for가 가장 빠르고 그 다음이 range-based for, std::for_each이고, iterator를 사용하는 경우가 가장 느림(for의 3배 정도).
std::set<>의 경우는?
for는 사용할 수 없으므로 제외.
결과
for_each: 141.654 range-based for: 143.641 iterator: 150.167
별 차이 없음.
2 notes · View notes
coldmund · 7 years
Text
bash
export
test1.sh
#!/bin/bash -e export CROSS='asdf' echo $CROSS ./test2.sh
test2.sh
#!/bin/bash -e echo 'test2' echo $CROSS
test1.sh 실행 결과
asdf test2 asdf
if-not
test.sh
#!/bin/bash XX=1 echo $XX echo $YY if ! [ $XX ]; then echo XX fi if ! [ $YY ]; then echo YY fi
test.sh 실행 결과
1 YY
variable
test.sh
#!/bin/bash -e testvar="asdf" echo testvar echo $testvar echo ${testvar} echo "$testvar" echo '$testvar'
test.sh 실행 결과
testvar asdf asdf asdf $testvar
결과 저장
test.sh
#!/bin/bash AAA="AAA" echo $AAA R1=$(cat test1.sh) echo $R1 R2=$(cat $AAA) echo $R2
AAA
AAAA
test.sh 실행 결과
AAA #!/bin/bash AAA="AAA" echo $AAA R1=$(cat test1.sh) echo $R1 R2=$(cat $AAA) echo $R2 AAAA
command line argument
test.sh
#!/bin/bash echo $# if [ $# -eq 0 ] then echo "more arguments..." exit fi for i in $* do echo $i done
test.sh 1 2 3 실행 결과
3 1 2 3
1 note · View note
coldmund · 7 years
Text
how to check if the given string is a valid file name
파일 저장 시 입력받은 string으로 파일명을 만들어야하는데, 파일명으로 사용할 수 없는 글자가 포함되어 있는지 check해야 함.
platform마다 조건이 다르고, 너무 복잡하게 하기 싫어서 영문 대/소문자, 숫자, '-', '_', '~', ' '(space)만 허용.
세가지 방법으로 테스트
#include <ctime> #include <chrono> #include <string> #include <iostream> #include <regex> bool findChar1(const char c) { if('a' <= c && c <= 'z') return true; if('A' <= c && c <= 'Z') return true; if('0' <= c && c <= '9') return true; if(c == '-' || c == '_' || c == '~' || c == ' ') return true; return false; } bool findChar2(const char c) { static std::string validCharacters("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_~ "); return !(validCharacters.find(c) == std::string::npos); } bool findChar3(const char c) { std::regex r("[a-zA-Z0-9\\-_~ ]"); static std::string str(1, ' '); str[0] = c; return std::regex_match(str, r); } int main() { char v[10000]; const int REPEAT = 100; for(int i=0; i<10000; ++i) v[i] = 32+(i%95); // 1 auto t1 = std::chrono::system_clock::now(); for(int j=0; j<REPEAT; ++j) for(int i=0; i<10000; ++i) findChar1(v[i]); auto t2 = std::chrono::system_clock::now(); auto diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; // 2 t1 = std::chrono::system_clock::now(); for(int j=0; j<REPEAT; ++j) for(int i=0; i<10000; ++i) findChar2(v[i]); t2 = std::chrono::system_clock::now(); diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; // 3 t1 = std::chrono::system_clock::now(); for(int j=0; j<REPEAT; ++j) for(int i=0; i<10000; ++i) findChar3(v[i]); t2 = std::chrono::system_clock::now(); diff = t2-t1; std::cout << std::chrono::duration<double, std::milli>(diff).count() << std::endl; return 0; } // PC(mingw g++ 7.1.0) // 6.001 // 52.005 // 175658
가장 쉽게 생각할 수 있는, char가 ascii값이라는 가정으로 확인하는 방법이 가장 빠르며, 가능한 글자들로 string을 만들어 find()함수 사용하는 방법이 두번째, std::regex가 가장 느림.
각 방법의 속도 차이가 크게 나며 특히 regex는...(원래 만들어진 목적 생각하면 당연하지만).
regex는 ubuntu 14의 gcc4.8에서 컴파일은 되지만 실행 시 crash 발생.
코드 line 수가 늘더라도 첫번째 방법 사용해야 함-_-
1 note · View note
coldmund · 7 years
Text
std::all_of(), std::accumulate()
어느날 생긴 의문
어떤 container의 멤버들에 대해 테스트를 가한 후 그 결과를 std::deque<bool>에 저장함(vector<>를 사용하지 않은 이유는 ESTL item 18 참고).
deque 안의 모든 결과가 true이면 함수의 결과가 true, 그렇지 않으면 false여야하는 상황.
std::all_of(), std::accumulate(), std::find()를 사용할 수 있을 텐데, short-circuit이 발생하는지? 그리고 어느 방법이 빠른지? 혹시 for를 사용해 short-circuit을 발생시키면 더 빠르진 않을지?
아래의 실행 결과는 cpp.sh에서 실행한 결과임.
short-circuit 발생 여부
#include <deque> #include <iostream> #include <algorithm> int main() { std::deque<bool> input{false, true}; std::cout << std::all_of(input.cbegin(), input.cend(), [](const bool x) { std::cout << '!'; return x; }) << std::endl; std::cout << std::accumulate(input.cbegin(), input.cend(), true, [](const bool x, const bool y) { std::cout << '!'; return x && y; }) << std::endl; std::cout << (std::find_if(input.cbegin(), input.cend(), [](const bool x) { std::cout << '!'; return x == false; }) == input.cend()) << std::endl; return 0; } // result: // !0 // !!0 // !0
위 코드 실행 결과 std::all_of(), std::find_if()는 short-circuit 발생하며 std::accumulate()는 short-circuit 발생하지 않음(당연히 predicate 안에서 발생할 side-effect를 유지하기 위해서 겠지).
따라서 std::find()도 short-circuit이 발생하리라 예상되고...
실행 속도
#include <iostream> #include <algorithm> #include <deque> #include <chrono> bool d1(const std::deque<bool> &in) { return std::all_of(in.cbegin(), in.cend(), [](const bool x) { return x; }); } bool d2(const std::deque<bool> &in) { return std::accumulate(in.cbegin(), in.cend(), true, [](const bool x, const bool y) { return x && y; }); } bool d3(const std::deque<bool> &in) { for(auto i : in) if(!i) return false; return true; } bool d4(const std::deque<bool> &in) { return std::find(in.cbegin(), in.cend(), false) == in.end(); } int main() { std::deque<bool> t1{false, false, false, false}; std::deque<bool> t2{true, false, true, false}; std::deque<bool> t3{false, true, false, true}; std::deque<bool> t4{true, true, true, true}; auto tm1 = std::chrono::system_clock::now(); std::cout << d1(t1) << d1(t2) << d1(t3) << d1(t4) << std::endl; auto tm2 = std::chrono::system_clock::now(); std::cout << std::chrono::duration<double, std::milli>(tm2-tm1).count() << std::endl; tm1 = std::chrono::system_clock::now(); std::cout << d2(t1) << d2(t2) << d2(t3) << d2(t4) << std::endl; tm2 = std::chrono::system_clock::now(); std::cout << std::chrono::duration<double, std::milli>(tm2-tm1).count() << std::endl; tm1 = std::chrono::system_clock::now(); std::cout << d3(t1) << d3(t2) << d3(t3) << d3(t4) << std::endl; tm2 = std::chrono::system_clock::now(); std::cout << std::chrono::duration<double, std::milli>(tm2-tm1).count() << std::endl; tm1 = std::chrono::system_clock::now(); std::cout << d4(t1) << d4(t2) << d4(t3) << d4(t4) << std::endl; tm2 = std::chrono::system_clock::now(); std::cout << std::chrono::duration<double, std::milli>(tm2-tm1).count() << std::endl; return 0; } // result(-O0) // 0001 // 0.049588 // 0001 // 0.004838 // 0001 // 0.003079 // 0001 // 0.004162 // result(-O2) // 0001 // 0.044687 // 0001 // 0.003287 // 0001 // 0.002384 // 0001 // 0.002644
(당연히) 결과는 같으며 속도는 for 문 사용한 경우가 가장 빠름.
의외로 std::all_of()가 std::accumulate()나 std::find()보다 10배 이상 시간이 많이 걸림.
for가 가장 빠르지만 더 sexy한 std::accumulate()나 std::find() 사용 예정~
1 note · View note
coldmund · 7 years
Text
chrono (c++)
Ratio
Represent rational number
Used in std::chrono::duration class
일반적인 object를 만들거나(compile-time constant) method를 호출할 수 없으며 typedef를 사용해야한다.
typedef ratio<1, 60> r1; // OK intmax_t n=1; intmax_t d=60; typedef ratio r2; // ERROR
library는 아래와 같은 값을 제공한다.
typedef ratio<1, 1000000000000000000000000> yocto; typedef ratio<1, 1000000000000000000000> zepto; typedef ratio<1, 1000000000000000000> atto; typedef ratio<1, 1000000000000000> femto; typedef ratio<1, 1000000000000> pico; typedef ratio<1, 1000000000> nano; typedef ratio<1, 1000000> micro; typedef ratio<1, 1000> milli; typedef ratio<1, 100> centi; typedef ratio<1, 10> deci; typedef ratio< 10, 1> deca; typedef ratio< 100, 1> hecto; typedef ratio< 1000, 1> kilo; typedef ratio< 1000000, 1> mega; typedef ratio< 1000000000, 1> giga; typedef ratio< 1000000000000, 1> tera; typedef ratio< 1000000000000000, 1> peta; typedef ratio< 1000000000000000000, 1> exa; typedef ratio< 1000000000000000000000, 1> zetta; typedef ratio<1000000000000000000000000, 1> yotta;
Duration
duration class는 tick의 수와 tick period를 저장한다.
tick period는 두 tick 사이의 초단위 시간이며 ratio로 표현된다.
template <class Rep, class Period = ratio<1>> class duration {...}
Rep는 tick의 수를 저장할 변수의 type이며, Period는 tick의 간격을 나타내는 rational constant이다(default는 1초).
산술연산과 비교연산이 가능하다.
example:
duration<long, ratio<60>> d3(10); // 10 minutes duration<long, ratio<1>> d4(14); // 14 seconds
library에 아래와 같은 값들이 정의되어 있다(X means "signed interger type of at least").
typedef duration<X 64 bits, nano> nanoseconds; typedef duration<X 55 bits, micro> microseconds; typedef duration<X 45 bits, milli> milliseconds; typedef duration<X 35 bits> seconds; typedef duration<X 29 bits, ratio<60>> minutes; typedef duration<X 23 bits, ratio<3600>> hours;
정수로 나누어지지 않는 값은 compile error를 발생시킨다. 이는 값에 의해 판단되지 않으며 type에 의해 판단된다. 아래 예의 두번째, 네번째 코드와 같이 초로부터 분을 얻을 경우 나누어지지 않을 가능성이 있으므로 error가 발생한다.
seconds s(90); minutes m(s); // ERROR seconds ss(60); minutes mm(ss); // ERROR
Clock
clock은 time_point와 duration으로 이루어진다.
표준은 3개의 clock을 정의한다.
steady_clock의 time_point는 작아지지 않는다.
system_clock은 언제든지 값을 변경할 수 있다.
high_resolution_clock은 가장 작은 tick period를 가진다. compiler에 따라 steady_clock이나 system_clock과 같을 수 있다.
각 clock은 현재 시간을 time_point로 얻을 수 있는 static method now()를 가진다.
C-style time_t와 time_point 간의 변경을 위해 to_time_t(), from_time_t() 함수를 제공한다.
auto start = system_clock::now(); // do some job auto end = system_clock::now(); auto diff = end - start; cout << duration<<double, milli>(diff).count() << "ms" << endl;
Time point
A point in time is represented by the time_point class and stored as a duration relative to the epoch.
time_point는 항상 특정 clock과 연관되어있으며 epoch는 연관된 clock의 origin이다. 예를 들어 classic Unix/Linux의 epoch는 1970년 1월 1일이며 duration은 초로 계산된다.
time_point는 epoch로부터 경과시간(duration)을 알려주는 time_since_epoch() 함수를 가진다.
가장 작은 값과 큰 값을 나타내는 static method min()과 max()를 제공한다.
1 note · View note
coldmund · 7 years
Text
Prefer task-based programming to thread-based
thread-based
int doAsyncWork(); std::thread t(doAsyncWork);
task-based
int doAsyncWork(); auto fut = std::async(doAsyncWork); // std::future type
task-based의 장점
std::async에서 return된 std::future의 get() 이용해서 결과를 얻을 수 있다.
exception을 잡을 수 있다(thread-based인 경우 프로그램이 죽게됨).
thread 관리를 자동으로 해줌.
thread 개수가 모자라거나 oversubscription될 경우에 대한 최적화. - thread 개수가 모자랄 경우 호출한 thread에서 get()을 실행.
thread를 사용해야할 경우
thread 구현(pthread, window thread)의 API를 이용해야할 경우(ex. priority 설정).
최적화를 직접 수행해야할 경우.
C++ standard API 외에 다른 threading 기술을 사용해야할 경우(ex. thread pool).
3 notes · View notes
coldmund · 8 years
Text
Consider void futures for one-shot event communication
thread 간 통신이 필요할 때 사용할 수 있는 방법들
condition variable
std::condition_variable cv; std::mutex m; // detecting task ... cv.notify_one(); // reacting task { std::unique_lock<std::mutex> lk(m); cv.wait(lk); ... }
problem
mutex의 원래 목적인 resource에 대한 접근 관리가 아닌 thread 흐름제어에 mutex를 이용함.
wait()보다 notify가 먼저 실행되면 reacting task가 종료되지 않음.
spurious wakeups에 의해 wait() 실패. 이를 해결하기 위해서 detecting task가 정상 동작했는지 확인 필요.
flag
std::atomic<bool> flag(false); // detecting task flag = true; // reacting task while(!flag) ; ...
problem
reacting task에서 대기하는 동안 polling 해야 함.
1, 2를 개선
std::condition_variable cv; std::mutex m; bool flag(false); // detecting task { std::lock_guard<std::mutex> g(m); flag = true; } cv.notify_one(); // reacting task { std::unique_lock<std::mutex> lk(m); cv.wait(lk, [] { return flag; }); ... } ...
problem
condition_variable과 mutex를 이용함.
future 이용
std::promise<void> p; void react(); void detect() { std::thread t([] { p.get_future().wait(); react(); }); ... // CAUTION! p.set_value(); ... t.join(); }
problem
promise와 future 간의 shared state를 dynamic allocation 하기위한 비용.
promise에 한번 값을 설정하고나면 이후 사용 불가.
"CAUTION!" 부분에서 exception 발생 시 thread t가 종료되지 않음.
1 note · View note
coldmund · 8 years
Text
CRTP and Static polymorphism
CRTP: Curiously recurring template pattern
발단은 어딘가의 Singleton 사용에 관한 코드를 보면서부터...
이게 뭐여...
class AuthenticationObserver : public Singleton // 'AuthenticationObserver'가 반복됨. { ... }
관련 자료
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
내용 중 Static polymorphism이 위 코드에 해당하는 내용이나 위키답게 정석적인 설명만 있고 뭔가 와닿는 내용이 없음.
https://wikidocs.net/495, https://wikidocs.net/501
잘 아는 분 같은데, 설명을 못 알아듣겠음.
http://alleysark.tistory.com/234
위 코드의 용도에 맞는 설명으로 보임. 부모클래스의 static 멤버를 상속받은 클래스에서 별도 메모리로 가지고 싶을 경우 사용.
특징
부모클래스와 자식클래스의 member 변수 중 static member가 별도 메모리를 가짐.
method의 경우 부모클래스에 인터페이스 함수 정의하여 이용.
일반적인 상속의 경우 run-time에 object-method binding이 이루어지지만, 정적 다형성을 적용할 경우 compile-time에 binding이 이루어지므로 실행속도가 빠르다(VTBL이 없음.) 단 binary가 커짐.
example
일반적인 상속의 경우
#include <iostream> class Singleton { public: static Singleton *instance() { static Singleton *inst = nullptr; if(inst == nullptr) inst = new Singleton(); return inst; } static int xxx; protected: Singleton() {} ~Singleton() {} }; int Singleton::xxx = 0; class Derived1 : public Singleton { public: static Derived1 *instance() { static Derived1 *inst = nullptr; if(inst == nullptr) inst = new Derived1(); return inst; } }; class Derived2 : public Singleton { public: static Derived2 *instance() { static Derived2 *inst = nullptr; if(inst == nullptr) inst = new Derived2(); return inst; } }; int main(int argc, char **argv) { Singleton *aa = Singleton::instance(); Singleton *bb = Singleton::instance(); aa->xxx = 10; std::cout << bb->xxx << std::endl; // 10 Derived1 *cc = Derived1::instance(); Derived2 *dd = Derived2::instance(); cc->xxx = 20; std::cout << bb->xxx << std::endl; // 20 std::cout << dd->xxx << std::endl; // 20 return 0; }
첫번째 출력의 경우 Singleton이 한 개의 instance만 가진다는 것을 보여준다. 두번째와 세번째 출력은 Singleton을 상속한 Derived1의 static variable의 값을 바꿀 경우 Singleton과 Derived2의 static variable의 값이 함께 바뀌는 것을 보여준다.
Static polymorphism
#include <iostream> template class Singleton { public: static T *instance() { static T *inst = nullptr; if(inst == nullptr) inst = new T; return inst; } static int xxx; static void interfaceFunc(int v) { T::implFunc(v); } protected: Singleton() {} ~Singleton() {} }; template int Singleton::xxx = 0; class Derived1 : public Singleton { public: static void implFunc(int v) { std::cout << "Derived1: " << v << std::endl; } }; class Derived2 : public Singleton<Derived2> { public: static void implFunc(int v) { std::cout << "Derived2: " << v << std::endl; } }; int main(int argc, char **argv) { Derived1 *cc = Derived1::instance(); Derived2 *dd = Derived2::instance(); cc->xxx = 10; std::cout << cc->xxx << std::endl; // 10 std::cout << dd->xxx << std::endl; // 0 (4-a) cc->interfaceFunc(100); // Derived1: 100 (4-b) dd->interfaceFunc(200); // Derived2: 200 (4-b) return 0; }
Singleton<>을 상속한 두 클래스-Derived1과 Derived2의 static variable의 값이 다르다.
Derived1과 Derived2에서 Singleton<>의 interfaceFunc()를 호출하여 derived class의 함수를 이용할 수 있다.
1 note · View note
coldmund · 8 years
Text
Smart pointer (c++)
auto_ptr
deprecated from c++11. 그 이전에도 사용할만한 물건이 아니었음.
STL container와 함께 사용해서는 안됨(ESTL 항목8).
unique_ptr
reference count 하지 않음. 할당된 memory를 가리키는 unique_ptr object는 한개 뿐임.
resource를 공유할 필요가 있는 경우에만 shared_ptr 사용할 것.
scope를 벗어날 경우(exception 포함) 자동으로 할당된 메모리가 해제됨.
auto mySimpleSmartPtr = make_unique(); // C++14 unique_ptr mySimpleSmartPtr(new Simple()); // C++11
기본은 new로 할당한 memory를 사용하지만 C-style array도 저장가능.
메모리 할당과 해제 방법을 변경할 수 있음(메모리 이외의 resource 관리에 사용할 수 있음).
shared_ptr
reference count 함.
thread-safe.
사용방법은 unique_ptr과 유사함.
auto mySimpleSmartPtr = make_shared();
unique_ptr과 달리 동적으로 할당된 C-style array는 저장할 수 없다.
auto myVariableSizedArray = make_unique(10); // OK, but not recommended auto myVariableSizedArray = make_shared(10); // NG.
shared_ptr은 reference count를 이용하지만 하나의 object를 가리키는 share_ptr을 여러개 만들면 안됨.
// crash or destructor called twice Nothing *myNothing = new Nothing(); shared_ptr smartPtr1(myNothing); shared_ptr smartPtr2(myNothing); // OK auto smartPtr1 = make_shared(); shared_ptr smartPtr2(smartPtr1);
weak_ptr
weak_ptr은 shared_ptr이 가리키는 memory를 가리킬 수 있으며 자신의 memory를 가지지 않는다.
shared_ptr은 weak_ptr의 존재와 관계없이 memory를 해제할 수 있다.
weak_ptr은 메모리를 해제할 수 없지만 shared_ptr의 memory가 해제됐는지를 판단할 수 있다.
move semantics
shared_ptr과 unique_ptr 모두 move semantic 지원함. 함수의 return 값으로 사용할 경우 move()에 의해 return 됨.
unique_ptr은 대입연산자 실행 시 move()를 반드시 사용해야 함.
auto p1 = make_unique(42); unique_ptr p2 = p1; // Compile error unique_ptr p3 = move(p1); // OK. p1 is reset to nullptr
0 notes
coldmund · 8 years
Text
Rvalue references & Move semantics (c++)
Rvalue references
C++의 lvalue는 named variable처��� 주소를 얻을 수 있는 것이며 rvalue는 그렇지 않은 것이다(예를 들어 상수, 임시 객체나 값).
rvalue reference는 rvalue에 대한 참조이며, 특히 rvalue가 임시객체일 경우 적용된다.
rvalue reference의 목적은 임시 객체가 사용될 경우 특정 함수를 선택할 수 있도록 하는 것이며 이를 이용해 덩치 큰 객체의 복사를 pointer의 복사로 구현할 수 있다.
함수의 parameter에 &&를 추가하여 표시한다(ex. type &&name). 정확히는 universal reference라고 한다던가...
일반적으로 임시객체는 const type&로 표시하지만 rvalue reference를 사용하는 overload된 함수가 있을 경우 임시 객체는 해당 함수로 처리된다.
// 1. lvalue reference void incr(int &value) { cout << "increment with lvalue reference" << endl; ++value; } // 2. rvalue reference void incr(int &&value) { cout << "increment with rvalue reference" << endl; ++value; } int a = 10, b = 20; incr(a); // call 1. incr(a + b); // call 2. incr(3); // call 2. incr(std::move(b)) // call 2.
Move semantics
object에 move semantics를 사용하기 위해서는 move constructor와 move assignment operator가 필요하다. 둘 다 source object로부터 member variable을 복사하고 source object의 variable은 null value로 초기화한다(shallow copy).
move constructor와 move assignment operator는 모두 noexcpet여야 한다.
class Spreadsheet { public: Spreadsheet(Spreadsheet &&src) noexcept; Spreadsheet &operator=(Spreadsheet &&rhs) noexcept; }; Spreadsheet::Spreadsheet(Spreadsheet &&src) noexcept { mCells = src.mCells; ... src.mCells = nullptr; ... } Spreadsheet &Spreadsheet::operator=(Spreadsheet &&rhs) noexcept { if(this == &rhs) return *this; freeMemory(); // remove previous value mCells = rhs.mCells; ... rhs.mCells = nullptr; ... return *this; }
move constructor와 move assignment operator가 없을 경우 copy constructor와 assignment operator가 사용되며 그 경우 위 code의 src.mCells = nullptr 대신 메모리 할당과 복사가 발생한다.
move constructor와 move assignment operator는 명시적으로 삭제되거나 기본값처리할 수 있다(explicitly deleted or defaulted).
std::move() 함수는 실제로 아무것도 옮기지 않는다. lvalue reference를 rvalue reference로 바꿀 뿐이다(EMC++).
rvalue를 assign할 경우 std::move() 함수를 명시적으로 호출하지 않아도 move assignment operator가 호출된다.
#include <iostream> #include <utility> class Foo { public: Foo() { std::cout << "constructor" << std::endl; } Foo(Foo &f) { std::cout << "copy constructor" << std::endl; } Foo(Foo &&f) noexcept { std::cout << "move constructor" << std::endl; } Foo &operator=(const Foo &f) { std::cout << "assignment" << std::endl; } Foo &operator=(const Foo &&f) noexcept { std::cout << "move assignment" << std::endl; } }; Foo f1() { Foo f; return f; } Foo f2() { return f1(); } int main(int argc, char **argv) { Foo f; std::cout << "TEST1" << std::endl; f = f1(); // move assignment std::cout << "TEST2" << std::endl; f = std::move(f1()); // move assignment std::cout << "TEST3" << std::endl; f = f2(); // move assignment std::cout << "TEST4" << std::endl; f = std::move(f2()); // move assignment return 0; }
1 note · View note