반응형

posix shm_open

저수준 open 함수와 같은 원형이다.

기존의 유닉스 파일 처리 개념을 확장하고, name은 항상 / 로 시작한다.

메모리의 일부를 파티션 공간처럼 만들고, 여기에 파일을 만들어 공유하는 방식이다.

 

int shm_open(const char *name, int oflag, mode_t mode);
int shm_unlink(const char *name)

삭제는 shm_unlink(const char *name)을 활용한다.

posix 공유메모리에는 디렉토리 개념이 존재하지 않기 때문에 name에 슬래시를 붙이면 안된다.

 

그리고 posix 공유 메모리는 리얼타임 라이브러리를 활용하기 때문에

컴파일 시에 rt 라이브러리를 링크해야 정상적으로 컴파일이 가능하다.

gcc -o source source.c -lrt

 

open과 shm_open 차이

open은 disk 파일 시스템의 파일을 이용하여 공유하고

shm_open은 메모리의 일부를 파일 시스템으로 표현한 /dev/shm에서 파일 개념을 표현한다.

 

#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <stdlib.h>
#include <stdio.h>

int main() {
    int fd, pagesize, length;
    caddr_t addr;
    pagesize = sysconf(_SC_PAGESIZE);
    length = 1 * pagesize;

    //m.dat 앞에 슬래시를 붙이면 안된다. posix 공유메모리에는 디렉토리가 존재하지 않기 때문이다.
    if ((fd = shm_open("m.dat", O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1) {
        perror("shm_odsafpen");
        exit(1);
    }

    if (ftruncate(fd, (off_t) length) == -1) {
        perror("ftruncate");
        exit(1);
    }

    addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t) 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        exit(1);
    }

    close(fd);
    strcpy(addr, "Ftruncate Test\n");


    return 0;
}

위 코드에서 파일 디스크립터인 fd를 close 하여도

addr에 해당 공유 메모리의 주소가 남아있기 때문에 strcpy를 활용하여 매핑한 메모리에 데이터를 정상적으로 쓰는 게 가능하다.

 

 

POSIX 공유 메모리의 삭제

공유 메모리를 삭제할 때는 shm_unlink를 이용하면 된다.

파일을 삭제하는 unlink와 동일한 구조이다.

 

만약 위의 코드처럼 mmap으로 공유 메모리의 주소를 맵핑하고 있다면

munmap으로 맵핑을 해제 한뒤 unlink로 파일을 삭제해야 한다.

 

만약 posix 공유메모리를 사용 중에 삭제하는 경우에는

리눅스에서는 새로운 프로세스는 공유 메모리에 연결이 불가능하고,

기존 프로세스들은 공유 상태를 유지하게 된다. 이는 표준안에는 명시되지 않은 현상이다.

 

 

 


 

 

POSIX 세마포어

posix 세마포어는 외부에서 접근 가능한 인터페이스 경로 유무에 따라

명명된 세마포어(named semaphore), 익명 세마포어(nameless/anonymous semaphore)로 구분된다.

 

 

익명 세마포어 생성

#include <semaphore.h>

int sem_init(sem_t *sem, int pshared, unsigned int value);

sem에는 생성된 posix 세마포어를 저장한다.

pshared에는 현재 프로세스에서만 사용할 때는 0을 두고, 여러 프로세스에서 공유를 목적으로 생성할 때는 0이 아닌 값을 둔다.

value는 초기화할 세모포어의 값으로 리소스의 수를 의미한다.

 

 

명명된 세마포어 생성

#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

sem_t *sem_open(const char *name, int oflag);
sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

저수준 open함수와 유사하고 결과로 세마포어를 얻는다. name은 항상 / 로 시작한다

value에는 익명 세마포어와 동일하게 초기화할 세마포어의 값으로 리소스의 수를 둔다.

 

생성된 세마포어는 /dev/shm/ 의 경로에 생성된다.

posix 공유 메모리 처럼 "/m.sem" 파일을 sem_open 하면,

/dev/shm/sem.m.set 파일이 생성된다.

 

oflag에는 O_CREATE와 O_EXCL이 사용 가능하다.

실패 시에는 SEM_FAILED를 반환한다.

 

 

posix 세마포어는 스레드 라이브러리를 사용하여 컴파일 할때 링크를 해주어야한다.

gcc -o source source.c -pthread

 

 

posix 세마포어 연산 : P

#include <semaphore.h>

int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

//timespec
struct timepec{
	time_t tv_sec;
    long tv_nsec;
};

posix 세마포어는 한 번에 -1씩만 가능하다. 리소스가 없는 경우(value == 0)이면 대기한다.

 

sem_wait는 리소스가 없으면 대기하고,

sem_trywait는 리소스가 없으면 에러를 반환하고, errno에 EAGAIN이 설정된다.

sem_timedwait는 리소스가 없으면 지정한 시간만큼 대기하고, 대기 이후에도 없으면 에러를 반환하고,

errno에 ETIMEOUT이 설정된다.

 

sem_timedwait는 UNIX 시간 표현으로 절대시간을 이용한다. 10초 대기를 하려면 현재 시간에 +10초를 해야 한다.

struct timespec ts_timeout;
ts_timeout.tv_sec = time(NULL) + 10;
ts_timeout.tv_nsec = 0;

if(sem_timedwait(psem, &ts_timeout) == -1){
	if(errno = ETIMEOUT){ /* handle timeout */}
	else { /* Otherwise */ }
}

 

posix 세마포어 연산 : V

세마포어에서 V 연산은 리소스를 +1 한다. 대기하는 경우는 없다. 실패하는 경우는

최대값(SEM_VALUE_MAX)보다 커지는 경우로, errno에 EOVERFLOW가 설정된다.

int sem_post(sem_t *sem)

 

 

 

posix 세마포어의 제거

익명 세마포어를 제거할 때는 sem_destroy를 사용한다.

프로세스가 종료되면 자연스럽게 세마포어가 해제되고, 직접 제거하고자 하는 경우에 사용한다.

int sem_destroy(sem_t *sem);

 

명명된 세마포어를 제거할 때는 sem_close, sem_unlink를 사용한다.

int sem_close(sem_t *sem);
int sem_unlink(const char *name);

 

sem_open에 대응하는 sem_close를 통해 닫는다.

생성된 세마포어 파일을 삭제하기 위해 sem_unlink를 사용한다.

반응형
반응형
 const jointest = await DB.getRepository(Post)
    .createQueryBuilder("post")
    .leftJoinAndSelect("post.imageFiles", "imageFiles.url")
    .where("post.id <= :id", { id: readedPostId })
    .orderBy({ "post.id": "DESC" })
    .limit(50)
    .getMany();

typeOrm으로 leftjoin후 50개의 객체를 리턴받는 것을 목표로 쿼리를 작성했지만

실제로는 객체가 50개가 리턴되지 않고 적은 숫자가 리턴되었다.

 

그 이유는 이렇게 쿼리를 작성하면 

실제 쿼리는 위의 사진과 같이 Post id가 여러개 중복된 결과를 바탕으로

객체를 만들어서 리턴해주기 때문에

즉 쿼리 결과 50개를 바탕으로 객체를 리턴해주어서 post 50개가 아닌 쿼리결과 50개에 해당하는 데이터를 받는 것이었다.

 

이런 문제를 해결하기 위해서는 조인 후 리밋을 거는 게 아니라

post에 미리 50개를 리밋 걸어서 얻고 그 후 조인을 해야 해결할 수 있다.

 

실제 쿼리문으로 치면 이런식으로 작성을 해야 하는 것이다.

select * from (select id, writer from post order by post.id desc limit 50) as post
left join image_file
on post.id = image_file.postId

 

 

그런데 검색을 하다보니 limit이 아닌 take를 사용하면 이 문제를 해결 할 수 있었다. 

const jointest = await DB.getRepository(Post)
    .createQueryBuilder("post")
    .where("post.id <= :id", { id: readedPostId })
    .orderBy({ "post.id": "DESC" })
    .leftJoinAndSelect("post.imageFiles", "imageFiles.url")
    .take(50)
    .getMany();

typeOrm pagination

https://orkhan.gitbook.io/typeorm/docs/select-query-builder#adding-offset-expression

 

Select using Query Builder - typeorm

There are two types of results you can get using select query builder: entities and raw results. Most of the time, you need to select real entities from your database, for example, users. For this purpose, you use getOne and getMany. However, sometimes you

orkhan.gitbook.io

 

반응형
반응형

안드로이드에서 레트로핏을 활용해 서버와 통신하는데 String 데이터를 주고받는 경우

다음과 같이 따옴표가 포함되어 전송되는 문제가 발생했다.



 

알고보니 이 문제는 레트로핏 서비스 인터페이스 작성시에 multipart를 이용하여 통신하는 경우

매개변수를 RequestBody로 하지 않고 String으로 두어 따옴표가 생겨서 전송되는 것이었다.

 

매개변수를 RequestBody로 두고 request 메시지를 보내면 따옴표가 포함되지 않고 텍스트만 전송이 가능하다.

 

 

 

반응형
반응형
#include <iostream>
using namespace std;
#define MX 101

int n, d[MX], dp[MX][MX], P[MX][MX];

void order(int i, int j){
    if(i==j){
        cout << "M" << i;
    }
    else{
        int k = P[i][j];
        cout << "(";
        order(i, k);
        order(k+1, j);
        cout << ")";
    }

}

int main() {
    int T;
    cin >> T;
    for (int t = 0; t < T; t++) {
        cin >> n;
        for(int i=0; i<=n; i++){
            cin >> d[i];
        }

        for(int diagonal=1; diagonal<=n-1; diagonal++){
            for(int i=1; i<=n-diagonal; i++){
                int j = i + diagonal;

                int minValue = 2e9;

                for(int k = i; k <j; k++){
                    int cur = dp[i][k] + dp[k+1][j] + d[i-1] * d[k] * d[j];
                    if(minValue > cur){
                        P[i][j] = k;
                        minValue = cur;
                    }
                }
                dp[i][j] = minValue;
            }
        }
        order(1, n);
        cout << '\n';
        cout << dp[1][n] << '\n';
    }
    return 0;
}
반응형
반응형

https://www.acmicpc.net/problem/2618

 

2618번: 경찰차

첫째 줄에는 동서방향 도로의 개수를 나타내는 정수 N(5 ≤ N ≤ 1,000)이 주어진다. 둘째 줄에는 처리해야 하는 사건의 개수를 나타내는 정수 W(1 ≤ W ≤ 1,000)가 주어진다. 셋째 줄부터 (W+2)번째 줄

www.acmicpc.net

#include <bits/stdc++.h>

using namespace std;

const int MX = 1'000'001;
int N, W, dp[1003][1003];

vector<pair<int, int> > work;

int lastMax = MX;
pair<int, int> lastWork;

int getMaxDistance(int A, int B) {
    if (A == W || B == W) {
        return 0;
    }
    int &ret = dp[A][B];
    if (ret != -1) return ret;

    ret = MX;
    int nextWork = max(A, B) + 1;

    int ret1 = -1, ret2 = -1;
    //다음 일을 A가 할 때
    if (A == 0) {
        ret1 = getMaxDistance(nextWork, B) + abs(1 - work[nextWork].first) + abs(1 - work[nextWork].second);
    } else {
        ret1 = getMaxDistance(nextWork, B)
               + abs(work[A].first - work[nextWork].first) + abs(work[A].second - work[nextWork].second);
    }

    //다음 일을 B가 할 때
    if (B == 0) {
        ret2 = getMaxDistance(A, nextWork) + abs(N - work[nextWork].first) + abs(N - work[nextWork].second);
    } else
        ret2 = getMaxDistance(A, nextWork)
               + abs(work[B].first - work[nextWork].first) + abs(work[B].second - work[nextWork].second);

    return ret = min(ret1, ret2);
}


void reconstruct(int A, int B) {
    if (A == W || B == W) return;

    int nextWork = max(A, B) + 1;
    int ret1 = -1, ret2 = -1;
    //다음 일을 A가 할 때
    if (A == 0) {
        ret1 = dp[nextWork][B] + abs(1 - work[nextWork].first) + abs(1 - work[nextWork].second);
    } else {
        ret1 = dp[nextWork][B]
               + abs(work[A].first - work[nextWork].first) + abs(work[A].second - work[nextWork].second);
    }

    //다음 일을 B가 할 때
    if (B == 0) {
        ret2 = dp[A][nextWork] + abs(N - work[nextWork].first) + abs(N - work[nextWork].second);
    } else
        ret2 = dp[A][nextWork]
               + abs(work[B].first - work[nextWork].first) + abs(work[B].second - work[nextWork].second);

    if (ret1 < ret2) {
        cout << 1 << '\n';
        reconstruct(nextWork, B);
    } else {
        cout << 2 << '\n';
        reconstruct(A, nextWork);
    }
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> W;

    work.push_back({0, 0});
    for (int i = 0; i < W; i++) {
        int a, b;
        cin >> a >> b;
        work.push_back({a, b});
    }

    memset(dp, -1, sizeof(dp));
    cout << getMaxDistance(0, 0) << '\n';
    reconstruct(0, 0);

    return 0;
}
반응형
반응형

 

package com.example.mythread;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    int value = 0;
    TextView textView;

    MainHandler handler = new MainHandler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        textView = findViewById(R.id.tv);

        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                BackgroundThread thread = new BackgroundThread();
                thread.start();
            }
        });
    }


    // 새로 생긴 쓰레드가 하는 일 지정
    class BackgroundThread extends Thread{
        public void run(){
            for(int i=0; i<100; i++){
                try{
                    Thread.sleep(100);
                }catch (Exception e){
                    Log.d("Thread", "run: " + e.toString());
                }
                value += 1;
                Log.d("Thread", "value: " + value);



                // 메시지 객체를 받아와서
                Message message = handler.obtainMessage();
                Bundle bundle = new Bundle();
                bundle.putInt("value" , value);
                message.setData(bundle);

                // 메시지 큐에 sendMessege를 한다.
                handler.sendMessage(message);
            }
        }
    }


    //메인쓰레드가 한다
    class MainHandler extends Handler {
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);

            Bundle bundle = msg.getData();
            int value = bundle.getInt("value");
            textView.setText("value 값 " + value);
        }

    }

}

 

 

 

handler의 post() 메소드를 이용하여 새로만든 Runnable 객체를 전달해 주면

이 객체에 정의된 run() 메소드 내의 코드들은 메인 스레드에서 실행된다.

이 경우에 Bundle을 이용해서 데이터를 주고받지 않아도

간결하게 코드를 작성할 수 있다.

package com.example.mythread;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    int value = 0;
    TextView textView;

    MainHandler handler = new MainHandler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = findViewById(R.id.button);
        textView = findViewById(R.id.tv);

        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                BackgroundThread thread = new BackgroundThread();
                thread.start();
            }
        });
    }


    // 새로 생긴 쓰레드가 하는 일 지정
    class BackgroundThread extends Thread{
        public void run(){
            for(int i=0; i<100; i++){
                try{
                    Thread.sleep(100);
                }catch (Exception e){
                    Log.d("Thread", "run: " + e.toString());
                }
                value += 1;
                Log.d("Thread", "value: " + value);


                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("value 값: " + value);
                    }
                });
            }
        }
    }


    //메인쓰레드가 한다
    class MainHandler extends Handler {
        @Override
        public void handleMessage(Message msg){
            super.handleMessage(msg);

//            Bundle bundle = msg.getData();
//            int value = bundle.getInt("value");
//            textView.setText("value 값 " + value);
        }

    }

}

 

반응형
반응형

안드로이드 주요 특징 및 아키텍처 소개

 

안드로이드 주요 기능

애플리케이션 프레임워크를 통해 제공되는 API를 사용하여 코드 재사용성을 높이고 빠른 개발이 가능하다.

모바일 기기에 최적화된 달빅 또는 아트런타임을 제공한다.

모바일용 데이터베이스인 SQLite를 제공한다.

각종 오디오, 비디오 및 이미지 형식을 지원하고, 모바일 기기에 내장된 각종 하드웨어(블루투스, 카메라, WIFI 등)을 지원한다.

이클립스 IDE, Android Studio를 통해서 빠른 개발 환경을 제공한다.

 

 


 

안드로이드 구조

안드로이드 구조

안드로이드의 구조는 응용 프로그램, 응용 프로그램 프레임워크, 라이브러리, 안드로이드 런타임, 리눅스 커널으로 이루어져 있다.

 

1. 응용 프로그램

안드로이드 스마트폰에서 사용할 수 있는 일반적인 응용 프로그램을 말하며,

예를 들어 웹 브라우저, 달력, 구글맵, 연락처, 게임 등 사용자 입장에서 가장 많이 사용된다.

응용 프로그램은 Java로 작성된다.

 

 

2. 응용 프로그램 프레임워크

안드로이드 API가 존재하는 곳이다.

안드로이드폰 하드웨어에 접근할 때는 API를 통해서만 가능하다.

 

 

3. 안드로이드 런타임

Java 코어 라이브러리와 달빅 가상 머신 또는 아트 런타임으로 구성된다.

안드로이드는 Java 문법으로 프로그래밍하지만 Java 가상 머신을 사용하지 않고 안드로이드 런타임에 존재하는

달빅 가상 머신이나 아트 런타임을 사용한다. 그 이유는 달빅 가상 머신이나 아트 런타임이 안드로이드 환경에 최적화되어 있기 때문이다.

 

 

4. 라이브러리

안드로이드에서 사용되는 여러 시스템 라이브러리는

시스템 접근 때문에 응용 프로그램과 달리 Java가 아닌 C로 작성되어 성능이 뛰어나며 세밀한 조작이 가능하다.

 

 

5. 리눅스 커널

하드웨어 운영과 관련된 저수준의 관리 기능이 들어있다.

메모리 관리, 디바이스 드라이버, 보안 등 많은 스마트폰 장치 기능을 지원한다.

카메라, 터치스크린, GPS, 자이로스코프 ...

 

 

 


 

안드로이드 개발 환경의 구성

안드로이드 개발 환경의 구성

 

1. JDK (Java Development Kit)

Java 환경에서 돌아가는 프로그램을 개발하는 데 필요한 툴들을 모아놓은 소프트웨어 패키지이다.

 

 

2. SDK (Software Development Kit)

소프트웨어 개발 도구 모음이라고도 한다.

SDK는 API, IDE, 문서, 라이브러리, 코드 샘플 및 기타 유틸리티가 포함될 수 있다.

안드로이드 앱 개발에서 안드로이드 SDK는 필수 요소이다.

 

 

3. ADT (Android Development Tools)

안드로이드 개발 도구를 의미한다.

 

 

4. AVD (Android Virtual Device)

AVD는 안드로이드 에뮬레이터에서 시뮬레이션 하려는

안드로이드 스마트폰이나 태블릿 등의 기기의 특성을 정의하는 구성이다.

AVD를 활용하여 안드로이드 스마트폰 없이 안드로이드 어플리케이션을 개발할 수 있다.

 

 

 

안드로이드 개발 환경별 특징

안드로이드 개발 환경 별 개발 툴킷

안드로이드에서 응용 프로그램을 개발할 때는 Java 언어를 사용하며 개발 툴킷은 SDK(Software Development Kit)를 사용한다.

시스템 응용 프로그램을 개발할 때는 C, C++ 언어를 사용하며 개발 툴킷은 NDK(Native Development Kit)를 사용한다.

하드웨어를 제어하고 커널 관련한 개발을 할 때는 C, C++언어를 사용하며 PDK(Platform Development Kit)을 이용하여 개발한다.

 

 

 

 

 

안드로이드 앱 개발 구성 요소

안드로이드 개발 구성 요소

 

1. 에뮬레이터 혹은 디바이스 

안드로이드 스튜디오에서 개발한 앱을 테스트한다.

 

2. adb(Android Debug Bridge) 프로그램

안드로이드 스튜디오를 실행하면 자동으로 실행되어 [에뮬레이터/디바이스]와 연결을 관리한다.

 

3. adbd(Android Debuf Bridge Daemon) 프로그램

안드로이드 디바이스 내부에서 adb 서버와의 통신을 담당한다.

 

4. Run 메뉴

[안드로이드 플러그인] -> [adb 서버] -> [adbd] -> [에뮬레이터/디바이스] 로 전송되어 실행된다.

 

5. 디버거(Debugger)

프로그램 버그를 찾기 위한 소프트웨어 앱을 직접 사용하거나 안드로이드 스튜디오에 내장된 것을 사용한다.

 

반응형
반응형

https://www.acmicpc.net/problem/16987

 

16987번: 계란으로 계란치기

원래 프로그래머의 기본 소양은 팔굽혀펴기를 단 한 개도 할 수 없는 것이라고 하지만 인범이는 3대 500을 넘기는 몇 안되는 프로그래머 중 한 명이다. 인범이는 BOJ에서 틀린 제출을 할 때마다 턱

www.acmicpc.net

#include <bits/stdc++.h>

using namespace std;

struct Egg {
    int s, w;
};

Egg arr[8];

int N , ans;

void DFS(int cur) {
    if (cur == N) {
        int cnt = 0;
        //깨진 계란 갯수 확인하기
        for (int j = 0; j < N; j++) {
            if (arr[j].s <= 0) cnt++;
            ans = max(ans, cnt);
        }
        return;
    }

    for (int i = 0; i < N; i++) {
        if(i==cur) continue;
        //단, 손에 든 계란이 깨졌거나 깨지지 않은 다른 계란이 없으면 치지 않고 넘어간다.
        if (arr[cur].s <= 0 || arr[i].s <= 0){
            DFS(cur+1);
            continue;
        }
        //손에 들고 있는 계란으로 깨지지 않은 다른 계란 중에서 하나를 친다.
        arr[i].s -= arr[cur].w;
        arr[cur].s -= arr[i].w;
        DFS(cur+1);
        arr[i].s += arr[cur].w;
        arr[cur].s += arr[i].w;
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> N;
    for (int i = 0; i < N; i++) {
        int s, w;
        cin >> s >> w;
        arr[i] = {s, w};
    }


    DFS(0);

    cout << ans << '\n';

    return 0;
}
반응형

+ Recent posts