1)한줄요약 : 머신러닝을 활용한 위험소리알림,오픈소스 활용한 음성인식기능,SOS기능,보호자 등록 기능을 가진 안드로이드 앱을 제작

+비상알림벨: 경적,화재경보음,아기울음소리 등 위험소리를 감지하여 그 종류를 알려준다. 소리데이터 즉각적인 인지를 위해 진동을 발생시키고, 소리를 분석하여 화면에 이미지로 출력한다.          

+소음측정기: 주변의 소음정도를 측정해 적절한 발화를 돕는다. 데시벨을 측정해 크기에 맞춰 LED를 점등시킨다.

+원터치 신고: 사회적 약자인 장애인을 겨냥한 범죄를 즉각 대처할 수 있도록 돕는다. 버튼을 특정 패턴으로 누르면 작동되어, 실시간으로 사용자의 위치와 녹음 파일을 서버로 전송한다.

+음성인식: 원활한 대화를 위해 상대방의 음성을 인식하여 모니터에 텍스트로 출력한다.

 

2)본인 역할 : 위험소리알림기능을 전담함. mfcc로 wav파일 특징값을 추출하고 ,svm으로 모델에 학습시켜 샘플의 분류결과값을 지정. 자신의 역할을 끝낸 뒤  안드로에드에서 모듈들을 합치는 것을 도와줌.

+팀원:천재영(웹),박진청(데이터베이스),이은경(소음측정기,음성인식),박신혜(원터치신고,구글맵)

 

3)본인이 사용한 스킬 : JAVA,Machine Learning(MFCC+SVM)

+팀원스킬: Google Map Api, Naver Speech Api,Android,PHP,Mysql

 

4)힘들었던 점: 

+머신러닝이 어렵고 낯설었던 점->기술 레퍼런스,구조도를 활용해 맥락을 파악하려고 노력하며 디버깅

+머신러닝 분류기 선택할 때 팀원들을 설득하던 것->분류기마다 특성을 정리해 SVM이 더 적합한 이유를 얘기

+추출기의 출력 포맷이 분류기의 입력 포맷과 달랐는데 추출기 내부 함수를 수정하기 어려웠음->다른 IDE에서 미니 전처리 프로그램을 따로 만듬. 추후에 내부 함수 또한 수정하는데 성공했음.

 

[전체구조도]

 

 

 

[미니전처리기를 통해 포맷팅을 한 결과]

 

[제공되는 GUI를 활용하는 모습- 라이브러리는 livsvm 사용]

[실제 프로젝트 결과 모델의 분류 정도]

 

 

[실제 완성본 모습-데시벨 증가하는 모습, 분류해서 push 알림으로 도착한 모습, 보호자 로그인 기능..(다른 기능들은 사진이 없다)]

 

 

 

 

 


그 외의 자료들...

 

[주요 코드 1]

 

package edu.iitb.frontend.audio.feature;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.Vector;

import javax.sound.sampled.AudioInputStream;

import javax.sound.sampled.AudioSystem;

import javax.sound.sampled.UnsupportedAudioFileException;

import edu.iitb.frontend.audio.util.AudioPreProcessor;

import edu.iitb.frontend.audio.util.MFCC;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.IOException;

 

 

public class FeatureFileExtractor {

    static float sampleRate = 8000;

    public static int newWindowSize = 205;

    public static int hopsize = 80;

    static int numberCoefficients = 13;

    static double minFreq = 133;

    static double maxFreq = 3500;

    static int numberFilters = 31;

    /*    테스트 코드

    public static void main(String argv[]) throws IOException, IllegalArgumentException, UnsupportedAudioFileException {

        FeatureFileExtractor t = new FeatureFileExtractor();

        t.computeFeatures("siren15", "/Users/KCE/Desktop/capstone/total_train_wav/siren", "/Users/KCE/Desktop/capstone/total_train_wav/siren");

    }*/

    static int label = 1;  //분류값

 

    public static void computeFeatures(String fileName, String inputFolder, String outputFolder)   //문제의 포맷팅 처리 부분..기존에 visual stuio로 수정했지만 eclipse에서도 수정할 수 있게 됐다!

            throws IllegalArgumentException, IOException, UnsupportedAudioFileException {

 

        // WAV파일 읽음

        String wavFile = inputFolder + "/" + fileName + ".wav";

        System.out.println("converting " + wavFile + " to mfc");

        File soundfile = new File(wavFile);

        AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundfile);

        AudioPreProcessor in = new AudioPreProcessor(audioIn, sampleRate);

        boolean useFirstCoefficient = true;

        

        //MFCC처리 

        MFCC feat = new MFCC(sampleRate, windowSize, numberCoefficients, useFirstCoefficient, minFreq, maxFreq,

                numberFilters);

        Vector<double[]> features = feat.process(in, audioIn);

        System.out.println("Vector Size :" + features.size());

 

        // 포맷팅

        BufferedWriter out = new BufferedWriter(new FileWriter("/Users/KCE/Desktop/capstone/not_trained_data/test.txt"));

        try {

            // create file output stream

            double arr[];

            for (int i = 0; i < features.size(); i++) {

                arr = features.get(i);

                if ((float) arr[0] < 30 && (float) arr[0] > -30) { // null

                    System.out.print(label + " "); // label

                    out.write(label + " ");        // label

                }

                for (int j = 0; j < arr.length; j++) {

                    if ((float) arr[j] < 30 && (float) arr[j] > -30) { // null

                        System.out.print(j + 1 + ":" + (float) arr[j] + " ");

                        out.write(j + 1 + ":" + (float) arr[j] + " ");

                        if (j == arr.length - 1)

                            System.out.println();

                        //String numberAsString = new Float((float) arr[j]).toString(); // float -> string

                        //out.write(numberAsString + " ");

                    }

                }

                if ((float) arr[0] < 30 && (float) arr[0] > -30) // null

                    out.write("\n");

            }

            out.flush();

            out.close();

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

 

 

 

 

[주요 코드 2]

 

import java.io.IOException;

import javax.sound.sampled.UnsupportedAudioFileException;

import edu.iitb.frontend.audio.feature.FeatureFileExtractor;

 

public class test {

 

    public static void main(String argv[]) throws IOException, IllegalArgumentException, UnsupportedAudioFileException

    {

        FeatureFileExtractor Feature = new FeatureFileExtractor();   

        Feature.computeFeatures("",                 // wavfile_name

                                "/Users/KCE/Desktop/capstone/total_train_wav/bark",     // input_file_dir

                                "/Users/KCE/Desktop/capstone/bark");    // output_file_dir

        svm_predict Predict = new svm_predict();

        String dir[] = {"/Users/KCE/Desktop/capstone/not_trained_data/test.txt",             // test_file(예측 시도해 볼 입력 파일)

                        "/Users/KCE/Desktop/capstone/model/traintrain.txt.model",    // model_file(모델파일이 있는 경로)

                        "/Users/KCE/Desktop/capstone/model/traintrain.txt.out"};        // output_file(예측 결과가 저장되는 경로)

        Predict.main(dir);   //만들어진 모델로 예측

        System.out.println(Predict.case_num);

        if(Predict.case_num==1)  //무슨 소리인지 분류 결과값 리턴

            System.out.println("baby");

        else if(Predict.case_num==2)

            System.out.println("bark");

        else if(Predict.case_num==3)

            System.out.println("drill");

        else if(Predict.case_num==4)

            System.out.println("fire");

        else if(Predict.case_num==5)

            System.out.println("siren");

    }

    

}

 

 

[프로젝트 진행사항 전달]

 

+참고자료: http://keunwoochoi.blogspot.kr/2016/01/blog-post.html : 다른 분류기를 사용하여 음악장르 분류 포스팅한 블로그

 

설명: 왼쪽부터 머신러닝 프로세스, 사용된 mfcc 파일,wav 파일이다.

원데이터는 분석을 위해 mp3아닌 wav파일 사용,프레임 길이 고려하여 5초 단위로 잘랐음. 축적된 데이터는 아기울음소리, 개짖는 소리, 사이렌소리,소방벨 소리 총 81개의 파일. 

 

 

 

 

 

'Project' 카테고리의 다른 글

[툰츄]  (0) 2019.11.06
[부귀영화-영화 추천 서비스]  (0) 2019.10.25
[WaterMelon-음원 사이트]  (0) 2019.10.25
[MARK- 길건너기 2D 게임]  (0) 2019.10.25
[hearable watch-청각장애인용 스마트 워치]  (0) 2019.10.25

1)한줄요약 : 유니티와 BFS알고리즘을 활용하여 기존의 지뢰찾기와 길찾기를 접목시킨 2D 게임을 제작

+룰:출발지에서 목적지까지 구멍들을 피해서 가장 적은 이동으로 도착해야한다.

가로,세로축의 트랩 수를 알려주는 등대와 자신  근처의 트랩 수를 알려주는 카운터는 추론의 보조장치가 된다.

게임중 목숨의 수는 줄어들 수 있고 아이템을 활용할 수 있다.

2)본인 역할 : 알고리즘 구현(BFS), 스토리 구성 

+팀원:ㅎㅈㅎ(PL,알고리즘 구현),ㄳㅎ(UI,스토리)

 

3)본인이 사용한 스킬 : C#,Unity

+팀원스킬: Google Map Api, Naver Speech Api,Android,PHP,Mysql

 

4)힘들었던 점: 

+팀원이 구조체에 대한 개념, 반복문으로 PS 하는 방법을 모르는 상태였어서 if~else가 백줄 가까이 작성되있었다. 

분담 후에 서로 진도 확인이나 결과물을 2주 가까이 한번도 점검하지 않았기 때문에 전혀 모르고 있었다. 

이미 열심히 만든 코드를 수정하는게 너무 미안했지만 이런 과정을 통해 알아가는거라고 생각을 다시 잡았다.

객체를 사용하고 이중포문을 이용해(Light House 코드..) 코드를 20줄 가까이로 최적화 시켰다. 

나의 첫 프로젝트였고 이 경험에서 나는 소통의 중요성을 배웠다.

 

5) 코드가 있는 깃허브 주소 (https://github.com/hun2ya9/2017-MARK)

 

 

[UI]

 

 

[오브젝트 소개]

[플레이어의 라이프는 게임실행 내내 반복되는 update함수에서 체크합니다. 마우스 입력을 통해 8방위로 이동가능하고

아이템을 활용하여 게임을 진행합니다.]

 

[ 플레이어 이동은 레이캐스트로 구현,마우스 클릭시 카메라로 부터 가상의 빔을 쏴서 해당 위치가 타일이면 플레이어가 그 위치로 이동방식이다.

이동 후 기존의 타일은 제거하고 새 플에이어 위치에 다시 생성함. 아이템획득은 box collider을 통해 구현함]

 

[길을 막는 경우같은 예외처리가 중요했다. 하지만 아래와 같은 이유들로, 기본적인 예외처리만 하고 길이 없는 경우에 재배치 하는걸로만 만들기로 함]

[동작 순서도]

[게임 시스템 구조-오브젝트 매니저가 게임의 핵심정보를 가지고 있으면 나머지 스크립트에서 그 정보를 활용함.

그리고 오브젝트 매니저는 UI매니저와 연결이 되어있고 UI에선 업적을 확인할때 파일매니저를 통해 참조를 함.]

 

[알고리즘 선택 이유]

최단경로를 찾을 때엔 많은 종류의 기법이 있었지만,

A*나 다익스트라,벨만포드 등은 그래프에 적합하고 우리의 게임은

맵 크기도 작을뿐더러 무엇보다 가중치가 없었기때문에 가장 간단한 BFS로 구현

 

 

[일정]

 

 


그 외의 자료..

[문제의 코드]

 

public void viewlight() //같은 행과 열에 지뢰가 몇 개 있는지

 

{

 

g = GameObject.FindGameObjectWithTag("Canvas").GetComponent<Text>();

 

int mapsize = Mathf.RoundToInt(script.gridWorldSize.x);

 

for (int x = 0; x < mapsize; x++) //등대 설치할 때 일차원배열에 바로 넣어줬으면 좋았으련만 시간이 없으므로 패스

 

for (int y = 0; y < mapsize; y++)

 

if (script.grid[x, y].is_lighthouse == true)

 

{

 

int trap_cnt = 0;

 

for (int i = 0; i < mapsize; i++)

 

{

 

if (script.grid[x, i].is_trap == true)

 

trap_cnt++;

 

if (script.grid[i, y].is_trap == true)

 

trap_cnt++;

 

}

 

g.text = trap_cnt + "";

 

GameObject G = Instantiate(Text);

 

G.transform.position = script.grid[x, y].worldPosition;

 

}

 

 

 

 

 

}

 

 

[유니티 환경. 그래픽 객체에 직접 코드를 연결한다는게 매우 편하고 놀라웠다.]

 

 

 

 

'Project' 카테고리의 다른 글

[툰츄]  (0) 2019.11.06
[부귀영화-영화 추천 서비스]  (0) 2019.10.25
[WaterMelon-음원 사이트]  (0) 2019.10.25
[Hearable App-청각장애인용 스마트 앱]  (3) 2019.10.25
[hearable watch-청각장애인용 스마트 워치]  (0) 2019.10.25

1)한줄요약 : 머신러닝으로 소리가 발생했을 때 위험한 소리인지 분석하여 릴리패드로 진동과 LED로 종류를 알림.

 

2)본인 역할 : 임베디드 파트. 릴리패드와 센서들을 연결하고 소리신호를 wav파일로 바꿔서 서버로 전송

+세부내용: 릴리패드의 마이크 센서에서 일정 수준 이상의 소음 입력되면 먼저 LED로 크기를 나타내고,

유의미한 소리라고 판단하여 녹음이 시작되며 서버에서 인공지능으로 분석후 종류를 알려줌.

+양우희(머신러닝),강창훈(임베디드,자바),김혜빈(머신러닝)

 

3)본인이 사용한 스킬 : Arduino, C ,LIly pad

+팀원스킬: Machind Learning(MFCC,HMM)+Matlab, JAVA

 

4)힘들었던 점: 

1.회로가 작동하도록 설계 했는데 전체를 연결하면 진동 센서가 동작 안함. 

->먼저 절차적으로 꼬이는 것이 있는지 확인을 해보고, 두번쨰로 모듈별로 코드를 분리해서 돌려봄.

-> 각각 돌렸을 때  이상이 없자 소프트웨어가 아닌 하드웨어 관점으로 접근해 생각해보았고 전력초과라는 원인을 찾아서 트랜지스터(전력을 증폭시키는 반도체소자)를 추가해서 해결.(아두이노로 연습당시)

2.분석에 필요한 녹음길이가 아두이노 메모리를 초과-> 실시간 전송 대신 서버에 저장해둔 녹음 파일을 분석하여 결과값을 자바의 시리얼 통신을 통해, LED를 이진수로 출력을 하였음.

 

5)아쉬운 점: 완성도가 높지 않았다. 추후에 버전 업그레이드 함( 링크:  포트폴리오로 정리한 "청각장애인용 스마트앱")

+왜 그랬을까? 하드웨어 스펙에 대한 조사가 충분히 이루어지지 않았다. (메모리 용량때문에 전체 wav 파일 녹음 불가, 시리얼통신으로 대체)

 

 

 

 

'Project' 카테고리의 다른 글

[툰츄]  (0) 2019.11.06
[부귀영화-영화 추천 서비스]  (0) 2019.10.25
[WaterMelon-음원 사이트]  (0) 2019.10.25
[Hearable App-청각장애인용 스마트 앱]  (3) 2019.10.25
[MARK- 길건너기 2D 게임]  (0) 2019.10.25

https://programmers.co.kr/learn/courses/30/lessons/12978

 

코딩테스트 연습 - 배달 | 프로그래머스

5 [[1,2,1],[2,3,3],[5,2,2],[1,4,2],[5,3,1],[5,4,2]] 3 4 6 [[1,2,1],[1,3,2],[2,3,2],[3,4,3],[3,5,2],[3,5,3],[5,6,1]] 4 4

programmers.co.kr

 

[주의할 조건]

마을의 개수 N은 1 이상 50 이하의 자연수입니다.

두 마을 a, b를 연결하는 도로는 여러 개가 있을 수 있습니다.

a, b(1 ≤ a, b ≤ N, a != b)

 

[구하는 값]

1번 마을에 있는 음식점이 K 이하의 시간에 배달이 가능한 마을의 개수를 return 하면 됩니다.

 

[생각의 흐름]

1번 지역에서 인접한 곳으로 이동하며 지나온 거리를 증가시키다가, K를 넘으면 이동을 하지 않는 방법으로 푼다.

dfs,bfs 무엇을 써도 무방하다.

dfs로 하면 한 마을에 인접한 마을의 최대 수가 50인데 한번 방문한 곳은 방문하지 않기 때문에

시간복잡도는 50x49x48...=250만.

백트래킹시에 방문체크 해제를 하지 않아야 재방문을 피한다.

 

인접마을을 표현할 땐 인접배열과 인접리스트 중에서 인접리스트를 썼다.

a->b로 가는 경로가 여러개가 있을 수도 있기 때문이다. 인접배열을 쓴다면

[a][b]에는 가중치가 하나만 저장된다. (->사실 최소로 갱신하면 되는데 이땐 몰랐다)
그래서 인접리스트로 표현을 했고, dfs 탐색시에 방문했던 마을이라고 무조건 안가는 것이 아니라

그 방문체크값을 확인해서 이전보다 빠른 경로로 왔다고 판단될 때에만 그곳을 가도록 만든다.
그렇기때문에 탐색이 진행되기 위해선 방문체크값의 초기값은 큰 수이어야 하며

이러한 탐색 방식을 다익스트라라고 한다.

 

그렇게 기존에 방문한 비용에 비해 절약된 비용으로 다른 노드를 갈 수 있다는 것에 의미가 있다.

 

 

[코드]

import java.util.ArrayList; 
import java.util.Arrays; 

class Solution {  //프로그래머스는 static으로 모두 선언해서 하지 않고 인스턴스 solution으로 돌리므로 다 인스턴스 변수여야 한다.   
   int ans=1;    //즉 메인 만들어서 돌려볼때 인스턴스로 접근해야 한다는 뜻. 대신 메인에서 무슨 기능 넣으면 안됨,,초기지역도 포함해야되서 1로 시작 
   int visit[]=new int[51];  //전역변수 할거는 전역변수로! 
   int K,N; 
   ArrayList<ArrayList<int[]>> adj=new ArrayList<ArrayList<int[]>>(); 
   public static void main(String[] args) { 
      int[][] arr= { 
            {1,2,1},{2,3,3},{5,2,2},{1,4,2},{5,3,1},{5,4,2} 
      }; 
      Solution m=new Solution(); 
      System.out.print(m.solution(5,arr,3)); 
   } 

    public int solution(int N, int[][] road, int K) {   
       Arrays.fill(visit,Integer.MAX_VALUE);  //수에 관한건 Integer에서, 배열 관련한 함수는 Arrays에! 
       this.N=N; 
       this.K=K; 
        for(int i=0;i<51;i++)  
           adj.add(new ArrayList<int[]>());  //이중어레 초기화 필요 
         
       for(int i=0;i<road.length;i++) { 
           adj.get(road[i][0]).add(new int[]{road[i][1],road[i][2]});  //int[]는 Integer처럼 쓰인다  
           adj.get(road[i][1]).add(new int[]{road[i][0],road[i][2]}); 
        } 
         
        dfs(1,0); 
        return ans; 
    } 
     
    public void dfs(int cur,int len) { 
       visit[cur]=len; 
        
       for(int[] nx:adj.get(cur)) { 
          if(nx[1]+len>K||visit[nx[0]]<nx[1]+len)  //다익스트라. 같은 지점 간다면 더 짧을때만 갈 수 있다. 
             continue;   //왜냐?a~b사이 가중치 여러개 있을 수 있어서 가봤다고 아예 안가면 안됨 
          if(visit[nx[0]]==Integer.MAX_VALUE)  //0이 안갔단 표시가 아님 
             ans++; 
          dfs(nx[0],nx[1]+len); 
       }    
    } 
} 

 




 

'PS' 카테고리의 다른 글

백준 17349 1루수가 누구야  (0) 2019.08.14
백준 17090 미로 탈출하기  (0) 2019.08.14
백준 13251 조약돌 꺼내기  (0) 2019.08.13

What?

여러 프로세스가 같은 자원을 기다리며 blocked된 상태.

롸?//지금 충분하게 있는 자원상태 혹은 자원이랑 뱉어낼 애 있는 상태 합,...<-이 시퀀스가 되면  safe하다고 함.

Why? 

상호배제(Mutual exclusion) : 한번에 여러 프로세스가 쓸 수 없는 자원이다

 

2.점유대기 : 자원을 사용중인 프로세스가 자원을 내놓지 않는다

 

3.비선점 : 다른 프로세스로부터 자원을 빼앗을 수 없다

 

4.순환대기 : 프로세스가 순환적으로 자원을 요구한다. 1번 자원을 사용하며 2번 자원을 기다리고, 2번 자원을 사용하며 3번 자원을 기다리고, 3번 자원을  사용하며 1번 자원을 기다리는 세 개의 프로세스.

Solution?

예방-> 데드락 성립조건 4가지중 하나라도 충족되지 않도록  만든다.

 

1.상호배제-> 상호배제 조건을 제거한다

 

2.보유대기->한 프로세스에게 가용 자원을 모두 할당시키고 결국 스스로 내놓게 만듬

Issue->일어나지도 않은 일을 위해 자원들 몰아서 써서 성능이 낮아진다.

 

3.비선점-> 선점 가능한 프로토콜을 만든다. (ex. 프로세스가 cpu 선점 시 상태를 저장해둠)

 

4.순환대기->사이클이 없도록 순서를 정한다.(ex.1번을 획득해야만 2번획득)

 

 

 

 

회피-> 미리 사용할 자원을 모두 정의해둔 것을 바탕으로 데드락을 발생시킬 가능성이 높은 프로세스에게는 자원 할당을 안해준다. 

 

실선은 자원을 사용중이라는 뜻, 점선은 언젠가 한번은 쓸 자원이라는 뜻일 때,

 

점선이 향하는 자원을 p1에게 주면 사이클이 생겨서 데드락이 발생할 것을 알고 자원을 할당해주지 않는다.

or

가용자원에서 최대를 쓸 수 있는 프로세스에게'만' 자원을 줘서 보유대기예방과 같은 효과를 낸다.(은행원 알고리즘)

 

 

 

 

발견->

 

1)자원할당그래프를 그려서 사이클을 찾아본다

그래프에 사이클이 있으면 데드락'일 수도 있다.'

(인스턴스가 하나면 무조건 데드락인데 인스턴스가 두개면..)

 

왼쪽: 데드락이다.

 

오른쪽: 데드락 아니다. 사이클이 있긴하지만 P4가 여분을 쓰다가 반납하면 쓸 수 있는 상황이기 때문이다. 

 

 

 

 

다양한 그래프 종류가 있다..

롸?// 사이클 찾는 시간복잡도? n^2! 간선 다 따라가보면 된느데

간선이 결국 하나에서 모든 곳에 다 뻗쳐도 n-1개기 때문.

 

 

 

 

 

 

 

2)자원할당테이블을 그려서 가용자원들 쌓아서 생각해보고 시퀀스가 가능한지 합쳐나가면서 체크한다.(추천)

 

 

a 7,b 2,c 6개가 있는데 allocation처럼 프로세스들에게 분할이 되어있는 상태이다. 

이 상태에서 p1,p2,p3,p4가 request와 같이 자원을 추가 요청한다.

이때, 가용자원은 없지만 낙관적으로 생각해서, p0같은 경우 반납할거라고 생각한다. 그럼  요청을 받아들이는 시퀀스가 존재하므로 다 만족할 수 있어서 데드락이 아니다 .

 

 

 

 

 

 

하지만 p2가 자원 c를 더 요청한다면 ,

요청한 자원도 만족할 때까지 본인이 가진 자원을 내놓지 않기 때문에 시퀀스가 불가능하고, 데드락이다.

 

 

 

 

 

 

 

 

*데드락은 최대한 낙관적이게 생각해도 데드락인 경우에만 데드락이라 판정한다*

 

 

회복->

1.모두 죽인다.

2.차례로 하나씩 죽여본다.

3.특정 기준으로 하나만 지목하여 죽인다.(Issue:꼭 자원이 적은걸로만 하면 기아현상 될수도..)

4.회복 안하고 무시한다.( 데드락 판별 알고리즘을 코드로 넣는 것 등은 성능을 저하시키므로, 차라리 인간이 직접 처리하는 것이 낫기 때문에 요즘 채택하는 방식이다.)

 

What?

동기화(同期化, synchronization)란, 말그대로 동시에 시스템을 작동시킬 수 있도록 만드는 것이다. 

그러므로 프로세스 동기화란, 멀티프로세스를 가능하게 만드는 것이다. 

이렇게 따로 용어까지 있는 정도면, 프로세스를 동시에 작동하는 것이 어떤 문제를 발생시킬 수 있을 정도로 중요한 문제가 될 수도 있다는 것이다. 바로 자원의 문제이다. 

 

 

먼저, 프로세스를 작동시키는 물리적인 주체는 cpu가 어떻게 프로세스를 작동시키는지,  자원을 어떻게 다루는지 보자..


*cpu 하나는 한번에 프로세스 하나만 처리할 수 있다.*

*프로세스는 ram 위에 작동되는 프로그램을 뜻하고, ram 위에는 프로세스마다 자신의 Code,Data,Stack에 대한 주소공간이 있다*

*cpu가 프로세스를 작동시키는 과정은 다음 그림과 같다*

'cpu'는 '프로세스의 주소공간'과 계속 데이터를 주고 받으며 동작한다. 

 

 

 

 

cpu는 하나의 프로세스 Data(on ram)에서 연산할 data를 가져와 연산을 하고, 연산 결과를 다시 Data(on ram)에 저장한다.

 

 

 

 

 

 

 

 

 

 


Issue?

그렇다. 한 프로세스의 주소공간은 다른 프로세스의 주소공간에 독립적이므로, Data 자원에 대해 문제가 생길 일이 없다. 하지만 프로세스 사이에 공유메모리(이전글)를 사용하는 경우라면, 얘기가 달라진다. 

 

예를 들어, a프로세스가 cnt란 변수를 1만큼 올렸는데, b프로세스가 cpu를 빼앗아서 cnt를 2로 올리고, 다시 a프로세스가 cpu를 빼앗으면 cnt를 1에서 이어서 올리는 것이 아닌, 2에서부터 올리게 되어 원래의 의도와 달라진다. 이것을 cpu를 빼앗기는 타이밍에 의해 Data의 일관성이 깨진다고 한다. 

 

 

Solution?

cpu가 하나인 경우) 프로세스 선택 정책을 선점이 아닌 비선점을 택하면 된다. 위의 경우에서, a프로세스가  cnt를 올리려고 했던만큼 완전히 올리기 전까진 b프로세스가 cpu를 뺏지 못하는 것을 의미한다. 

 

cpu가 여러개인 경우) 프로세서 자체가 구분되어 있어서 자원에 접근하는 것을 막을 방법이 없다. 그래서 커널에서 을 걸어서, 커널이 자원에 한 프로세스만 접근하도록 결정한다. 피터슨 알고리즘, 세마포어, 모니터가 있다. 

 

먼저, 용어에 대해 정리하고 가자. 


(lock 상호배제 or mutex or mutual exclusion):  동기화 메커니즘

 

 

Issue에서 설명한 것과 같이, 공유 자원에 대해 여러 개의 프로세스가 동시에 접근을 시도할 때 접근의 타이밍이나 순서 등이 결과값에 영향을 줄 수 있는 상태경쟁상태라고 말한다. 

 

 

 

 

 

 

공유자원 중에서도, 둘 이상의 스레드 동시에 접근해서는 안되는 코드의 일부크리티컬 섹션,임계구역, 공유변수라고 말한다. 

 


1)피터슨 알고리즘(소프트웨어적 락):

 

자신 프로세스의 turn=0, 다른 프로세스의 turn=1 일 때(각각 다른 프로세서가 맡았을 때) 0을 기준으로 while(turn!=0)은 1의 순서인 동안 루프만 돌며 임계영역에 진입하지 않는다는 뜻이다. 1의 순서가 끝났으면 자신 프로세스는 루프를 지나 critical section에 진입하고, 볼 일을 다 보면  다시 turn=1로 순서를 바꾸어준다. 다른 프로세서의 turn 1 프로세스는 자신의 차례이니 critical section에 진입한다. 

 

 

Issue->cpu는 instruction 단위로 빼앗길 수도 있어서, critical section 중도에 뺏기면  turn을 돌려놓지 않고 빼앗기는 것이기 때문에 다른 프로세스에서는  turn의 값이 바뀔때까지 기다리고, 자신 프로세스 또한 cpu를 뺏긴 상태기 때문에  <progress,진행 문제>와 <스핀락> 현상이 일어날 수도 있다.

 

progress,진행 문제:  아무도 critical section에 들어가지 않는 상태

스핀락,바쁜대기: critical section에 진입이 가능할 때까지 루프를 돌면서 재시도하는 상태(cpu와 메모리를 계속 써서 낭비함)

더보기

스핀락은 운영 체제 스케줄링 지원을 받지 않기 때문에, 해당 스레드에 대한 문맥 교환이 일어나지 않는다. 따라서 스핀락은 임계 구역에 짧은 시간 안에 진입할 수 있는 경우에 문맥 교환을 제거할 수 있어 효율적이다. 하지만 만약 스핀락이 오랜 시간을 소요한다면 다른 스레드를 실행하지 못하고 대기하게 되며, 이 경우 비효율적인 결과를 가져온다

 

 

2)Test and Modify(하드웨어적 락):

 

 

 instruction 단위로 cpu 뺏길수도 있어서 생기는 위의 문제를 

하드웨어적으로 instruction이 끝날때마다 flag 바꿔주는 것을 지원하는 방법이다. 

 

Issue->여전히 프로그래머의 실수가 영향을 미친다는 단점을 가지고 있다.

 

 

 

 

3)세마포어: 

 

 

위의 방식들을 추상화시킨 방법이다. 

세마포어 S는 정수값을 가지는 변수이고, P와 V라는 명령으로만 접근할 수 있다. 

즉, 한 프로세스(또는 스레드)에서 세마포어 값을 변경하는 동안 다른 프로세스가 동시에 이 값을 변경해서는 안 된다.

 

 

방법1...스핀락 사용

P(S) { while S <=0; // 아무것도 하지 않음 (반복문)  S--; } 자원 얻음

V(S) { S++; }  자원 반납

 

방법2...슬립락 사용(바쁜대기를 보완하여, cpu와 메모리를 쓰지않는동안 넘겨준다 )

P(S) { S--; if S < 0 // 이 프로세스를 재움 큐에 추가 (block) }  가용자원 없으니 block하는거다. 1편 참고

V(S) { S++; if S <= 0 // 재움 큐로부터 프로세스를 제거 (wakeup) } 되돌려줬는데도 음수란건 누군가가 음수로 만들고 block되있는 상태라는걸 뜻한다. block된  프로세스를 깨운다.

 

Issue->여전히 프로그래머의 실수가 영향을 미친다는 단점을 가지고 있다.

 

 

 

 

 

 

 

 

 

종류: 이진 세마포어(0또는 1만 가질 수 있고 mutex구현을 위해 사용한다), 계수 세마포어(그 외. 다른 프로세스가 접근 못한다는 특성을 이용해서 자원카운팅만 할 때 사용한다)

 

 

 

4)모니터(최종보스)

 

고급 언어(Java)에서 이 기능을 지원하며, 한번에 하나의 프로세스만 모니터에서 활동하도록 보장해준다. 모니터는 안에 공유변수 넣어두고, 공유변수 접근하는 함수들을 내부에 모아둔다.그리고 자체적으로 활동 가능한 함수는 하나만 되도록 만듬.프로세스가 모니터에 들어가고자 할 때 다른 프로세스가 모니터 내부에 있다면 입장 큐에서 기다려야 한다.

 

 

 

Difference?

세마포어는 스핀락이라 자원낭비가 생기거나, 보완된 방식을 사용해도 block 때문에 문맥교환 비용이 증가하는 반면

모니터는 입장 큐에 대기만 하면 되기 때문에 그 비용이 발생하지 않는다. 또한, 락을 거는 것이 아니기 때문에 자원을 더 쓸 수 있어서 효율적이다

 

 

 

 

위에서 나왔던 모든 Issue를 처리한 상태로 동기화한 것을 thread safe라고 한다.

 

 

//자바의 String 관련 동기,비동기도 알아보자

//생산자,공급자 ..배고픈 철학자 등 건넜음

//세마포어,뮤텍스 구현 한번 해보면 좋을듯

 

(1)프로세스 생성

 

What? 프로세스를 생성하는 방법은 부모프로세스가 자식프로세스를 낳는 것이다.

즉, 프로세스를 복제시키는 것이다. 

 

How? 리눅스에서는 fork()함수를 호출해서 생성한다

code,data,stack+pc까지 복제해서 생성된다.

다음에 exec()함수를 호출해 새로운 프로그램을 올린다.

main부터 코드 실행하다가 fork (시스템콜,운영체제 필요)만나면 프로세스 하나 만들고 아무 일 없듯이 다시 아래 코드 실행한다.자식은 문맥을 복사했기 때문에 부모가 pc가 어디에 멈춰있는지 알아서 그 다음부터 실행한다.

즉, 자식은 if부터 시작한다는 말!(물론 fork반환은 각각 다르게 리턴되서 각자 실행하는 코드분기 다르다)

 

+cpu는 한번에 하나 프로세스인데 동시에 실행된다고? 스레드가 아닌데?

...더보기

->그게 바로 멀티 프로세싱! 

엄밀히 말해 한 개의 CPU를 가진 개인용 컴퓨터가 특정 순간에 수행할 수 있는 태스크의 개수는 하나뿐이다. 따라서 멀티태스킹은 스케줄링이라는 방식을 사용하여 컴퓨터 사용자에게 병렬 연산이 이루어지는 것과 같은 환경을 제공한다. 스케줄링 방식은 CPU 사용시간을 일정한 기준에 따라 나누어 각 태스크가 사용할 수 있도록 분배한다. 

ㄴ출처:위키백과

 

 

Why?

1.fork 전의 리소스(간단히 variable이라고 함)를 자식프로세스가 복사해 가지는 것인데, 리소스자체가 많으면 무거워지는 단점이 있지만(그래서 쓰레드가 나온걸로 알고 있습니다), 자식프로세스와 부모프로세스간 또는 자식프로세스간의 통신을 위해서 IPC의 동일한 키값을 갖기 위해서는 이것만큼 쉬운 방법이 없다. 직접 멀티 프로세스 프로그램을 해 보시면 느낄 수 있다고 한다.

 

2.동일한 프로세스의 여러 인스턴스를 매우 효율적으로 만들 수 있다. 예를 들어 웹 서버에 여러 클라이언트가 동일한 프로세스를 여러 개 제공 할 수 있습니다. 다른 프로세스를 생성하는 비용이 현재 프로세스를 복제하는 비용보다 훨씬 큰 경우는 스레드를 사용하지만 공유자원때문에 오류가 생길 확률이 높아진다.

 

+exec라는 시스템콜도 있지만 걔는 완전히 새로운 프로세스를 실행하는거다.

exec()라는 함수 호출 뒤의 코드는 실행불가능하다.

 

+wait()은 자식프세가 끝날때까지 기다려줌. sleep으로 잠들어있는다.기존과 다르게 부모-자식이 원래 프로세스 사이의 모양답게 경쟁이었는데 잠시 협력으로 모양이 변함.

 

+exit()

자발적 종료:컴파일러가 위치를 잡아줌. 스스로 종료

비자발적: 프세법칙이 부모보다 자식이 먼저 죽는거랬다. 부모가 kill같은 사용자로부터 멈춰짐을 당하면 함수 타고 내려가서 자식들 다 죽이고 자신도 죽음->근데 독립적인데 어케 말함?아, 트리형태로 저장이랬지

혹은 부모가 자식이 자원 너무 많이 써서 죽이는 경우. 프세 우선순위가 부모인갑다..

 

프로세스 원칙적으로 독립적(지 변수 지만 봄.자신만의 주소공간 가짐).하지만 가끔 협력해야하는 경우 두가지 방법 씀.

1.쉐어드 메모리(면접쓰):물리적으로 변수 공유(커널한테 미리 말해야됨)

2.메시지 통신:필요한 것 커널통해서 메시지로 서로 전달

 

하나의 프로그램 안에서 통신을 위해 메모리를 사용하는 일은 일반적으로 공유 메모리로 부르지 않는다.

 

 

물리적으론 램에 있다

 

 

~스레드간의 협력도 기대해라~

 

프로세스들 보면 cpu만 주루룩(cpu burst) 쓰는게 많은 프로세스가 있고

IO만 주루룩(IOburst) 쓰는게 더 많은 프로세스가 있는데 이 둘이 교차 됨.

근데 사용자가 더 체감크니 IO프로세스에 좀 더 자원 줌.

 

그래서 CPU 스케줄러&디스패쳐 필요!

스케줄러는 뭐로 되있니?하드?소프? -> 운체 안에 코드로 있다

스케줄러가 결정을 내리면 디스패쳐가 실질적으로 문맥교환 도와주는거임

 

그래서 그게 언제 어떻게 적용되는데??

 

 

 

1은 나 cpu더 못써~io로 간다 해서 일어나는거

2는 한 애가 cpu 너무 오래 못쓰게 방지하려고 일어나는거

..

+선점형(뺏아서 바꿈),비선점형 있음(자진반납으로 바꿈)

 

 


(2)CPU스케줄링

 

2가지 이슈로 나뉜다.

 

1.다음에 누구에게 줄건지 2.강제로 할건지 끝나면 할건지

->현대는 선점형!

 

5가지로 성능을 평가할 수 있다.

 

1. cpu사용량:주방장이 놀지않고 일하는 비율

2.대기시간:밥먹는 시간말고 기다리는 시간

3.소요시간:들어왔다가 나가기까지

4.처리한 양:손님 얼마나 받았냐

5.응답시간: 첫 밥 먹기까지 걸린시간.중요. 초반에 단무지라도 주며 기다려야함.

 

그래서, 이런 종류들이 있다.(어디에 쓰면 좋을지랑 예제 하나 풀어보며 해보자)

 

1.FCFS: 온 순서대로. 비선점

앞에 긴거오면 다른 프로세스들 입장에서 겪는 대기시간

길어짐 (waiting시간 증가)

고민해보자..공평성이 중요할 때 좋을듯!티켓팅

 

그럼 짧은거 먼저 앞으로 땡겨올까?

2.SJF:짧은거 먼저

nonpre,pre 다 있는데 

pre는 스케줄 되있다가도 중간에 더 짧은애 오면 뺏음(참고로 계속 기준은 앞으로 더 써야하는 시간, 즉

남은 시간이다). 뺏는거라 대기 시간은 더 짧아짐

화장실생각! 대기가 치명적일떄!

+근데 더 짧은애 와도 강제없이 기다리면 그게 그냥 fcfs아닌가?

ㄴㄴ!계산해보면 뭔 차인지 안다. 먼저 온 애가 길어서 일단 실행중일때

큐에 쌓여있으면 그 중에서 스케줄링 하는거임.

 

 

 

 

->하지만 기아현상 발생!긴거는 영원히 못먹을수도..

꼭 대기중에 자기보다 짧은애만 들어오는 경우!

->실제cpu얼마나 잡을지 예측을 못하지만 예측공식(예전거 토대로) 있긴함

ㄴ왜하는거? 이미 계산되있는거 아녔나?->예측하고 들어왔는데 인터럽트 등으로 더 길어졌을때

본래 의도대로 가장 먼저 있는게 아니게 되니..예측을 사용하는 거임 

 

3.우선순위큐:우선순위 젤 높은 애 한테 줄래. 우선순위는 다양하게 정의.

pre,nonpre.

사실 sjf도 결국 cpu타임이 기준인 우선순위큐임.

->그래서 마찬가지로 aging이라는 현상발생..

오래기다리면 순위높여주는걸로!

 

4.라운드로빈:가장 현대적!할당시간 세팅해서 줬다가 뺏고 다시 주고...

->공평해서 기아현상 ㄴㄴ!쓸 시간 예측도 불필요!

프세 길면 퀀텀도 길게 줌. 하긴 안그러면 오버헤드 많이 붙어서 더 안좋을듯.

지나치게 퀀텀 짧을때의 예시기도 함.

 

+스케줄링으로도 모자라서 큐를 여러층으로 분리해서 더 최적화를 했다!

 

위의 큐일수록 우선순위 주고 아래일수록 안주는데 그렇게하면

starvation 생길 수 있으니 일단 위의 큐에 담기되 퀀텀내에 안끝나면

다음 순위 큐(퀀텀 김)로 밀려남.RR에서도 긴거일수록 퀀텀 길게 줬으니까.

큐마다 적용하는 스케줄링 다르다! 윗큐에 있다는건 빠르게 진행된단거니까

IO버스트가 짧게 자주 있거든, 그래서 거기엔 RR..

 

 

 

 

 

 

+Realtime스케줄러:데드라인 있어서 그 데드라인까지 각각 끝낼 수 있도록 먼저 스케줄링해두는 방식

하드-반드시 지켜야함

소프트-우선순위를 둠

 

+쓰레드 스케줄러:

로컬-운체가 일단 cpu를 프로세스에게 넘기면 그 뒤로 사용하는건 알아서 하도록 하는거

글로벌-운체가 쓰레드까지 스케줄링에 관여하는 것

 

  

지금까지 cpu하나 얘기였는데 여러개면 더 복잡~~

그리고 여기서 내가 더 주목할건

멀티프로세서랑 멀티프로세싱(앞에 위키백과 올린거)이 다르다는거!

멀티프로세싱은 cpu가 하나일수도 있지만 프로세서는 아니다.

 

 

 

 

 

 

 

성능비교 위해서 실제로 시뮬한다.(과제 있는듯)

원래 독서를 즐기는 사람이 아니라면, 책을 읽게 만드는 환경이 있어야 읽는 것 같다.

나 또한 취준을 하기 전까진 독서모임도 나가고, 집근처 반디앤루니스에서 신작을 읽곤 했는데

바빠지니 다시 활자와 멀어지게 된 기분이다. 하지만 얼마 전에 아이패드를 구입했기 때문에!

지하철 타는 시간에 틈틈이 읽어보려고 한다.

 

#아이패드 무료 책읽기 ㅎㅎ

전자책으로는 ㅁㄹㅇㅅㅈ라는 앱도 있지만, 나처럼 조금씩만 읽는 사람들은 월정액 뽕을 못뽑을거 같아서

전자도서관을 찾아보았다. 

 

방법은 두 가지다.

1.자신이 대학을 졸업했다면 해당 학교에서 지원해주는 전자도서관 이용

2.자신이 사는 지역의 전자도서관 이용

 

솔직히 나는 1번을 추천한다. 

부산만 그런건지 모르겠지만, 부산전자도서관은 책의 종류가 별로 없다. 그리고 부산 사람들이 모두 이용하는 곳이라 그런지 조금만 인기있는 책은 모두 대출이 차있다ㅠ

 

1번 방법:

00대학교 전자도서관 검색->있으면 회원가입->이용가이드를 찾아서 지원하는 ebook 앱을 찾는다(보통 교보전자도서관,yes24전자도서관 등이 있다)->해당 전자도서관 앱 설치->자신의 학교 이름 검색->즐겨찾기 및 학교 아이디로 로그인->대출

 

2번 방법: 1번처럼 간단하면 이 포스팅을 쓸 필요가 없지만.. 부산 전자도서관 홈페이지를 누가 만든건지 아주...이용하기 불편하다.ㅎ

 

부산전자도서관을 이용하려면 먼저 가까운 도서관에 직접 가서 통합회원카드를 발급 받아야 한다.

 

요렇게 생겼다. 이걸 발급 받으려면 직접 도서관에 가야한다.(신분증 지참!)

 

카드가 있다면 부산전자도서관 홈페이지로 이동한다. 

 

 

http://contents.siminlib.go.kr/FxLibrary/

 

부산전자도서관

 

contents.siminlib.go.kr

 

 

이 사이트에서 우리가 주의해야할 점이 많다.

 

1. ID/PW찾기,회원가입 버튼이 로그인 페이지에 없기 때문에 해당 서비스를 이용하려면 홈페이지 첫 화면의 로그인 창 내부의 아이디/비밀번호 찾기 링크를 통해야만 한다.

 

 

 

 

 

 

 

 

 

<- 아이디/비밀번호찾기 바로 여기!

 

 

 

2. 신규회원가입을 하면 내 회원번호를 보여주며 이미 있는 회원이라고 빠꾸먹이고,

아이디나 비밀번호 찾기를 하면 등록되지 않은 회원이라고 나온다. 

->통합도서서비스를 신청한 사람이 이용하는 것이라서 신규회원가입 오른쪽의 통합인증센터 링크에서 가입을 해야한다.

 

3.통합인증센터 및 신규회원가입 버튼은 화면 상단에 있다. 존재감이 없으니 주의하자!

 

 

 

정보를 입력하고 나면 가입이 완료되고, 전자도서관 홈페이지 첫 화면으로 돌아가 로그인을 하면 된다.

 

그리고 홈페이지의 이용안내에 따라서 PC에서 읽으려면 PC 안내룰, 태블릿 PC나 스마트폰에서 읽을 경우

모바일 안내를 따르면 된다. 나의 경우 모바일 안내에 있는 앱중에서 yes24를 깔았다.

https://contents.siminlib.go.kr/FxLibrary/help/mobileGuide

 

부산전자도서관

 

contents.siminlib.go.kr

 

'yes24 전자도서관' 앱을 깔고 실행하면 다음의 화면과 같다. 여기서 부산전자도서관을 검색한다.(즐겨찾기도 하자)

 

 

 

들어가면 로그인 창이 뜨는데 이때 아까 정보입력을 했던 아이디와 패스워드를 입력하면 로그인 된다. 

 

원하는 책을 검색하고 대출하면 드디어 읽을 수 있다!! 그런데 책의 종류가 진짜 어느 정도인지 잘 모르겠다..ㅠㅠ

가장 읽고 싶었고  오래된 책 '향수'도 없고 '언어의 온도'도 없다.. 웬만하면 대학 전자도서관 서비스를 이용하자!!

+ Recent posts