이전에 프로젝트를 만들었지만 프로젝트에 기능을 추가하기 위해서는 앱을 생성해야한다.

(mysite) stdiohan@stdiohan-MacBookPro mysite % django-admin startapp pybo
(mysite) stdiohan@stdiohan-MacBookPro mysite %

파이참 터미널에 django-admin startapp pybo 를 입력해 앱을 생성한다.

왼쪽 탭을 확인해보면 pybo 디렉토리와 하위 파일들이 생성되었다

브라우저에서 http://localhost:8000/pybo 페이지를 요청했을때 "안녕하세요 pybo입니다." 라는 문자열을 출력해보자

먼저 터미널에 python manage.py runserver 를 입력해 로컬서버를 구동한다.

(mysite) stdiohan@stdiohan-MacBookPro mysite % python manage.py runserver

그후 브라우저에 http://localhost:8000/pybo  를 검색하면

Page not found(404) 오류가 나온다

장고는 오류가 발생하면 오류의 원인을 화면에 자세히 보여주어서 오류를 파악하기가 쉽다. 오류를 해석하면 요청한 URL은 http://localhost:8000/pybo 이다. 오류 해결방법은 config.urls 파일안에 URLconf를 정의하라고 나온다. 그렇다면 그대로 해주면 된다. urls.py 파일은 페이지 요청이 발생하면 가장 먼저 호출되는 파일이다.

config.urls 파일은 projects/mysite/config/urls.py 에 있다.

urls.py 파일을 찾아 수정해준다

19줄에 from pybo import views , 23줄에 path('pybo/', views.index), 를 추가해준 모습이다. 의미는 'pybo/' 라는 URL이 요청되면 views.index 를 호출하라는 매핑을 urlpatterns 에 추가한것이다. views.index 는 views.py 파일의 index 함수이다. pybo/ 에 / 를 추가하는 이유는 URL 을 정규화하는 장고의 기능 때문이다.

아직 views.index 를 설정하지 않았기 때문에 이 상황에서 다시 페이지를 요청하면 페이지 연결 실패가 나올것이다.

views.py 파일을 수정한 모습이다

views.py 파일에

from django.http import HttpResponse

def index(request) :
        return HttpResponse("안녕하세요 pybo입니다.")

를 작성해 넣어보자 HttpResponse는 요청에 대한 응답을 할때 사용한다. index 함수의 매개변수 request 는 HTTP요청 객체이다.

작성을 했으면 다시 페이지를 요청해보자.

설정한 문자열이 정상적으로 출력된 모습이다

 

지금까지 한 이 과정들은 앞으로 장고를 개발할때 반복하는 계속 반복하는 과정이다.

 

[URL 분리방법]

 

urls.py 파일을 수정해서 앞으로 pybo/page1/create 등 이런형식의 URL을 추가해야할때 config/urls.py 를 수정할 필요없이 pybo/urls.py 만 수정해 작동할수있게 해보자.

config/urls.py 를 수정한것이다

전에 적었던 urls.py 와 달라진것이 보일것이다. path('pybo/', include('pybo.urls')) 의 의미는 pybo/ 로 시작하는 페이지를 요청하면 알아서 pybo/urls.py의 파일의 매핑정보를 읽어서 처리하라는 뜻이다. pybo/urls.py 파일 보고 처리하라고 했으니 파일을 만들자.

Pybo폴더에 마우스 오른쪽 클릭 - New - File 을 한 후 파일명을 urls.py 로 파일을 만든다. 그리고 파일 안에는

사진과 같이 파일을 수정하자

사진과 같이 파일내용을 추가하자. path('',views.index) 을 보면  이전에 설정한 config/urls.py 과 다른 부분은 이 있다. 저번에 적었던 'pybo/' 가 생략되고 '' 가 들어간 이유는 이미 config/urls.py 파일에서 이미 pybo/ 로 시작하는 URL이 pybo/urls.py 파일과 먼저 매핑되었기 때문이다.

config/urls.py 에 입력한 pybo/ 와 이번에 적은 '' 이 합쳐져 최종 URL 이 'pybo/' 가 되는것이다. 만약 다른 URL 을 추가해 pybo/page1/ 을 만들고싶다면 config/urls.py 에 적은 pybo/ 와 pybo/urls.py 에 새로 양식에 맞게 'page1/' 을 적어 넣는다면 최종 URL 은 config/urls.py 에 적은 pybo/ 와 pybo/urls.py 에 적은 page1/ 이 합쳐져 pybo/page1/ 이 되는것이다.

오류가 발생한다면 로컬서버를 재시작 하면 해결된다.

 

 

 

 

'Django > 따라하는 장고' 카테고리의 다른 글

6. 모델 사용법  (0) 2022.10.13
5. 장고 모델 작성법  (0) 2022.10.13
3. 파이참 사용하기  (0) 2022.10.11
2. 장고 프로젝트 생성  (0) 2022.10.11
1. 파이썬과 장고설치  (1) 2022.10.10

생능출판사 명품 운영체제

 

본 연습문제들은 작성자 본인이 푼것이라 틀릴 수 도 있습니다.

 

[개념체크]

 

1. 스레드가 도입된 배경으로 프로세스의 문제점을 잘못 설명한 것은?

④ 프로세스 스케줄링의 복잡성을 줄이려 했다

 

2. 프로세스와 스레드의 관계에 대한 설명으로 틀린 것은?

③ 프로세스는 자신에게 속한 모든 스레드의 부모이다

 

3. 멀티태스킹 프로그램을 작성하는데 있어서 각 태스크를 프로세스로 만드는 것과 스레드로 만드는 방법 중 스레드로 만드는 방법이 유리한 이유로 맞는 것은?

② 프로세스들은 주소 공간이 완전히 분리되어 있어 공유 공간을 만들기 위해 운영체제의 도움을 받아야 하지만, 멀티스레드를 이용하는 경우 프로세스 내에 공유 변수 등을 통해 쉽게 통신할 수 있기 때문이다

 

4. 스레드에 관한 정보를 저장하는 구조체를 무성이라고 부르는가?

TCB

 

5. 다음 중 다른 한가지는?

TLS(Thread Local Storage)

 

6. 다음 중 프로세스와 스레드 중 선택하여 문장을 완성하라.

운영체제의 실행 단위는 ( 스레드 ) 이며, ( 프로세스 ) 는 ( 스레드 ) 들이 공유하는 환경을 제공한다. ( 프로세스 ) 들은 각각 독립적인 메모리  공간에서 실행되므로 ( 프로세스 ) 사이에 데이터를 주고받는데 심각한 어려움이 있다. 응용프로그램을 실행시키기 위해 운영체제는 ( 프로세스 ) 를 만든다. 하나의 ( 프로세스 ) 가 실행되면 반드시 한 개의 ( 스레드 ) 가 자동으로 만들어지고 이것은 ( 스레드 ) 라고 부른다. 하나의 ( 프로세스 ) 는 여러 개의 ( 스레드 ) 를 가질 수 있다. ( 프로세스 ) 가 실행중이라는 뜻은 ( 프로세스 ) 속한 ( 스레드 ) 중 한 개의 ( 스레드 ) 가 현재 CPU에 의해 실행되고 있음을 뜻한다. 그러므로 운영체제 스케줄러에 의해 스케줄되는 단위는 ( 스레드 ) 이며, ( 프로세스 ) 에 속한 모든 ( 스레드 ) 가 종료할 때 ( 프로세스 ) 도 종료된다.

 

7.  다음 설명은 concurrency와 paralleism 중 어떤 것인지 선택하라.

(1) 1개의 CPU가 여러 스레드를 번갈아 실행할 때 cocurrency

(2) 2개의 CPU에서 2개의 스레드가 각각 동시에 실행될 때 paralleism

(3) CPU가 스레드의 입출력으로 인해 유휴(idle) 상태에 있지 않고 다른 스레드를 실행할 때 cocurrency

(4) 멀티 코어 CPU가 여러 스레드를 같은 시간에 동시에 실행할 때 paralleism

 

8. 다음 그림은 스레드 T1, T2, T3 가 실행되는 과정을 보여준다. cocurrency인가, parallelism인가?

cocurrency 이다

 

9. 스레드가 활동하는 코드, 데이터, 힙, 스택은 어떤 메모리 공간에 형성되는가?

스레드가 속한 프로세스 주소 공간 내에

 

10. 스레드의 주소 공간에 대한 설명으로 틀린 것은?

스레드 코드는 프로세스의 공간 밖에 별도의 공간에 적재된다

 

11. 스레드 로컬 스토리지(TLS)란 어떤 메모리 공간인가?

① 다른 스레드가 접근할 수 없는 스레드만의 사적인 공간이다

 

12. 스레드 A가 malloc(100)을 이용하여 동적 할당받은 100바이트 공간에 대해 틀리게 설명한 것은?

스레드 A가 종료할 때 할당받은 100바이트 공간은 자동 반환되지 않는다

 

13. TCB에 저장되는 내용이 아닌 것은?

스레드 크기

 

14. TCB에 저장되는 내용이 아닌 것은?

스레드 시작 시간

 

15. 다음 중 스레드 스케줄링이 일어나는 시점이 아닌 것은?

스레드가 시스템 호출을 하여 커널로 진입한 직후

 

16. 프로세스 컨텍스트 스위칭과 스레드 컨텍스트 스위칭을 비교하여 잘 설명하지 못한 것은?

프로세스 컨텍스트 스위칭이 개념적으로 스레드 컨텍스트 스위칭보다 단순하다

 

17. 스레드 운용에 관한 설명 중 틀린 것은?

스레드가 종료되면 스레드가 속한 프로세스도 종료된다

 

18. 스레드 라이브러리에 포함된 것이 아닌 것은?

스레드에서 파일을 여는 함수

 

19. 커널 레벨 스레드의 정의는 무엇인가?

커널에 의해 스케줄되는 스레드

 

20. 사용자 레벨 스레드의 정의는 무엇인가?

스레드 라이브러리에 의해 스케줄되는 스레드

 

21. 사용자 레벨 스레드의 장점이 아닌 것은?

여러 스레드가 각 코어에서 동시에 실행될 수 있기 때문에 멀티 코어 CPU를 가진 시스템에 적합하다

 

22. 커널 레벨 스레드의 장점은?

여러 스레드가 각 코어에서 동시에 실행될 수 있기 때문에 멀티 코어 CPU를 가진 시스템에 적합하다

 

23. 최근 들어 운영체제는 사용자가 만든 스레드를 커널 레벨 스레드로 구현하는 추세이다. 그 이유는 무엇인가?

① 응용프로그램에서 생성한 각 스레드를 멀티 코어 CPU에 할당하여 응용프로그램 실행에 높은 병렬성을 얻을 수 있기 때문

 

24. N개의 사용자 레벨 스레드를 1개의 커널 레벨 스레드로 매핑하는 N:1 매핑의 최대 단점은 응용프로그램에 속한 한개의 사용자 레벨 스레드가 입출력을 수행하여 볼륵 상태가 되면 응용프로그램 내의 다른 모든 사용자 레벨 스레드가 스케줄(실행)될 수 없다는 점이다. 이 과정을 자세히 설명하라.

사용자 레벨 스레드가 입출력을 수행하여 커널 레벨 스레드가 Blocked 상태가 되면 N:1 매핑이기 때문에 다른 사용자 레벨 스레드가 있음에도 불구하고 응용프로그램 전체가 중단된다. Blocked 상태가 되면 CPU 코어가 다른 커널 레벨 스레드를 할당해 다른 작업을하다 Blocked 상태가 Ready 상태로 바뀌어 커널 스케줄러에 의해 스케줄될 때 까지 기다려야한다.

 

25. 사용자 레벨 스레드와 커널 레벨 스레드의 매핑 기법으로 최근에 가장 많이 사용하는 것은?

② 1:1

 

26. 사용자 레벨 스레드와 커널 레벨 스레드의 매핑 기법으로 1:1 기법을 현재 가장 많이 사용하는 이유는?

매핑 개념이 단순하여 구현하기쉽다. 높은 병렬성을 제공하기 때문에 멀티프로세서를 가진 현대의 컴퓨터 시스템에 매우 적합하다. N:1 모델과 달리, 사용자 레벨 스레드 중 하나가 시스템 호출 중 블록 상태가 되어도, 응용프로그램 내 다른사용자 레벨 스레드는 여전히 스케줄링 가능하므로 응용프로그램 전체가 중단되는 일은없다. N:M 모델은 매핑과 스케줄링 과정이 복잡하여 현대의 운영체제에서는 거의 사용하지 않는다.

 

 

[복합 문제]

 

1. 그림 4-5의 맛보기 프로그램을 참고하여, 리눅스에서 다음 5가지 조건에 부합하느 멀티스레드 C 응용프로그램을 작성하라. 4개의 스레드를 활용하여 1에서 40000까지의 합을 구하여 출력한다.

(1) pthread 라이브러리를 이용하여 작성하라.

(2) 응용프로그램에 0으로 초기화된 전역 변수 int sum[4]를 선언하라.

(3) 스레드로 실행할 함수의 이름을 runner로 하라.

(4) main()에서 pthread_create() 함수를 활용하여 4개의 스레드를 연속적으로 생성하여 4개의 스레드를 동시에 실행시켜라.

- 스레드 1 : 1~10000 까지의 합을 구하고 sum[0]에 저장
pthread_create(... ... runner,"1"); //1에서 10000까지 합 구하기
- 스레드 2 : 10001~20000 까지의 합을 구하고 sum[1]에 저장
pthread_create(... ... runner,"10001"); //10001에서 20000까지 합 구하기
- 스레드 3 : 20001~30000 까지의 합을 구하고 sum[2]에 저장
pthread_create(... ... runner,"20001"); //20001에서 30000까지 합 구하기
- 스레드 4 : 30001~40000 까지의 합을 구하고 sum[3]에 저장
pthread_create(... ... runner,"30001"); //30001에서 40000까지 합 구하기

(5) main()은 4개의 스레드가 모두 종료하기를 기다린 후 sum[] 배열의 값을 모두 합쳐 그 결과를 화면에 출력하라. 다음은 이 프로그램의 이름이 prac4_1.c라고 할 때 컴파일 과정과 실행 결과를 보여준다.

$ gcc -o prac4_1 prac4_1.c -lpthread
$ ./prac4_1
1에서 40000까지 4개의 스레드가 계산한 총 합은 800020000
$

 

 

#include <pthread.h> // pthread 라이브러리를 사용하기 위해 필요한 헤더 파일 
#include <stdio.h>
#include <stdlib.h>

void* runner(void *param); // 스레드로 작동할 코드(함수) 
int total = 0; // main 스레드와 runner가 공유하는 전역 변수  
int sum[4] = { 0 };
int j = 0;
int main() {
        pthread_t tid1; //  스레드의 id를 저장할 정수형 변수 
        pthread_t tid2; //  스레드의 id를 저장할 정수형 변수 
        pthread_t tid3; //  스레드의 id를 저장할 정수형 변수 
        pthread_t tid4; //  스레드의 id를 저장할 정수형 변수 
        pthread_attr_t attr; // 스레드 정보를 담을 구조체 

        pthread_attr_init(&attr); // 디폴트 값으로 attr 초기화 
        pthread_create(&tid1, &attr, runner, "1"); // runner 스레드 생성
        pthread_create(&tid2, &attr, runner, "10001"); // runner 스레드 생성 
        pthread_create(&tid3, &attr, runner, "20001"); // runner 스레드 생성 
        pthread_create(&tid4, &attr, runner, "30001"); // runner 스레드 생성 
	// 스레드가 생성된 수 커널에 의해 언젠가 스케줄되어 실행 
        pthread_join(tid1, NULL); // tid 번호의 스레드 종료를 기다림
        pthread_join(tid2, NULL); // tid 번호의 스레드 종료를 기다림 
        pthread_join(tid3, NULL); // tid 번호의 스레드 종료를 기다림 
        pthread_join(tid4, NULL); // tid 번호의 스레드 종료를 기다림 
        for (int i = 0; i < 4; i++) {
            total += sum[i];
        }
	printf("1에서 40000까지 4개의 스레드가 계산한 총 합은 %d\n", total);
}

void* runner(void *param) { // param에 "값" 전달 
        int to =  atoi(param); // to = "값"
        int tmp = 0;
        total = 0;
        for (int i = to; i <= to + 9999; i++) { // to에서 to+9999까지 합계산 
            tmp += i;
        }
        sum[j] += tmp;
        j++;
}

 

2. 앞의 문제 1을 수정하여 리눅스에서 5가지 조건에 부합하는 멀티스레드 C 응용프로그램을 작성하라. 4개의 스레드를 활용하여 1에서 40000까지의 합을 구하여 출력한다.

(1) pthread 라이브러리를 이용하여 작성하라

(2) 응용프로그램에 전역 변수 int sum을 선언하고 0을 초기화하라.

(3) 스레드로 실행할 함수의 이름은 runner로 하라

(4) main에서 pthread_create() 함수를 활용하여 4개의 스레드를 연속적으로 생성하여 4개의 스레드를 동시에 실행시켜라.

- 스레드 1 : 1~10000 까지의 합을 구하고 sum에 합산
pthread_create(... ... runner,"1"); //1에서 10000까지 합을 sum에 합산
- 스레드 2 : 10001~20000 까지의 합을 구하고 sum에 합산
pthread_create(... ... runner,"10001"); //10001에서 20000까지 합을 sum에 합산
- 스레드 3 : 20001~30000 까지의 합을 구하고 sum에 합산
pthread_create(... ... runner,"20001"); //20001에서 30000까지 합을 sum에 합산
- 스레드 4 : 30001~40000 까지의 합을 구하고 sum에 합산
pthread_create(... ... runner,"30001"); //30001에서 40000까지 합을 sum에 합산

(5) main은 4개의 스레드가 모두 종료하기를 기다린 후 sum 값을 화면에 출력하라. 다음은 이 프로그램의 이름이 prac4_2.c라고 할 때 컴파일 과정과 여러 번의 실행결과를 보여준다. ( 실행결과가 실행할 때 마다 달라진다. )

$ gcc -o prac4_2 prac4_2.c -lpthread
$ ./prac4_2
1에서 40000까지의 스레드가 합친 sum 변수의 값은 583862451
$ ./prac4_2
1에서 40000까지의 스레드가 합친 sum 변수의 값은 640209990
$ ./prac4_2
1에서 40000까지의 스레드가 합친 sum 변수의 값은 500849160
$

1에서 40000까지의 합은 문제 1의 결과에 따라 800020000인데, 앞의 결과 화면에는 80020000가 출력되지 않는다. 여러 번 실행해도 계속 다른 값이 출력된다. 그 이유는 무엇인지 나름대로 설명해보라.

#include <pthread.h> // pthread 라이브러리를 사용하기 위해 필요한 헤더 파일 
#include <stdio.h>
#include <stdlib.h>

void* runner(void *param); // 스레드로 작동할 코드(함수) 
int total = 0; // main 스레드와 runner가 공유하는 전역 변수  
int sum = 0;
int main() {
        pthread_t tid1; //  스레드의 id를 저장할 정수형 변수 
        pthread_t tid2; //  스레드의 id를 저장할 정수형 변수 
        pthread_t tid3; //  스레드의 id를 저장할 정수형 변수 
        pthread_t tid4; //  스레드의 id를 저장할 정수형 변수 
        pthread_attr_t attr; // 스레드 정보를 담을 구조체 

        pthread_attr_init(&attr); // 디폴트 값으로 attr 초기화 
        pthread_create(&tid1, &attr, runner, "1"); // runner 스레드 생성
        pthread_create(&tid2, &attr, runner, "10001"); // runner 스레드 생성 
        pthread_create(&tid3, &attr, runner, "20001"); // runner 스레드 생성 
        pthread_create(&tid4, &attr, runner, "30001"); // runner 스레드 생성 
	// 스레드가 생성된 수 커널에 의해 언젠가 스케줄되어 실행 
        pthread_join(tid1, NULL); // tid 번호의 스레드 종료를 기다림
        pthread_join(tid2, NULL); // tid 번호의 스레드 종료를 기다림 
        pthread_join(tid3, NULL); // tid 번호의 스레드 종료를 기다림 
        pthread_join(tid4, NULL); // tid 번호의 스레드 종료를 기다림 
	printf("1에서 40000까지 4개의 스레드가 계산한 총 합은 %d\n", sum);
}

void* runner(void *param) { // param에 "값" 전달 
        int to =  atoi(param); // to = "값"
        total = 0;
        for (int i = to; i <= to + 9999; i++) { // to에서 to+9999까지 합계산 
            sum += i;
        }
}

스케줄링에 의해 4개의 스레드가 실행되는 순서가 계속 달라지기 때문에 매번 값이 달라진다.

생능출판사 명품 운영체제

 

본 연습문제들은 작성자 본인이 푼것이라 틀릴 수 도 있습니다.

 

[개념체크]

 

1. 다음글에서 프로세스와 프로그램 중에서 선택하라.

( 프로그램 ) 은 컴파일되어 실행 가능한 형태로 저장 장치에 저당된 상태일 때 부르는 용어이며, ( 프로세스 ) 는 메모리에 적재되어 실행 중인 상태일 때 부르는 용어이다

 

2. 프로세스의 특징을 설명한 것 중 맞는것은?

프로세스를 스케줄링 하는 것은 커널 기능이다

 

3. 프로세스에 대한 설명으로 틀린 것은?

동일한 프로그램이 실행되어 생성된 프로세서는 항상 동일한 프로세스 번호를 할당받는다.

 

4. PCB에 들어 있는 정보가 아닌 것은?

④ 프로세스 이름

 

5. 프로세스의 종료코드는 어디에 저장되는가?

프로세스의 PCB

 

6. 프로세스가 종료될 때, 커널이 프로세스 테이블 항복이나 PCB를 즉각 삭제하지 않는 이유는 무엇인가?

프로세스 종료코드를 부모 프로세스가 읽어갈 때까지 기다리기 위해

 

7. 32비트 CPU에 대해 다음에 답하여라.

(1) CPU의 주소선 개수는? 32개

(2) CPU가 액세스 가능한 메모리의 최대량은? 4GB

(3) 이 CPU를 사용할 때 프로세스의 주소 공간 크기는? 4GB

 

8. 프로세스의 주소 공간에 대한 설명으로 맞는 것은?

프로세스가 실행되는 동안 접근할 수 있는 메모리의 최대 범위이다.

 

9. 프로세스가 메모리에 적재될 때 프로세스를 구성하는 4개의 영역은 무엇인가?

코드 영역, 데이터 영역, 힙 영역, 스택 영역

 

10. 운영체제는 프로세스를 코드, 데이터, 힙, 스택의  4 영역으로 구성한다. 다음은 어느 영역에 형성되는가?

(1) 전역 변수 : 데이터 영역

(2) 지역 변수 : 스택 영역

(3) C++에서 new 연산자나 C 프로그램에서 malloc() 함수를 호출하여 할당받은 메모리 : 힙 영역

(4) 사용자가 작성한 함수 코드 : 코드 영역

(5) 라이브러리에 작성된 함수 코드 : 코드 영역

(6) 라이브러리 함수에 선언된 지역 변수들 : 스택 영역

 

11. 프로세스가 적재된 이후 실행 과정 동안 크기가 변하지 않는 영역을 있는 대로 골라라.

코드 영역,데이터 영역

 

12. printf()는 C 프로그램에서 화면 출력을 위해 사용되는 C 표준 라이브러리 함수이다. 다음 질문에 답하라.

(1) printf() 함수의 코드는 프로세스의 코드 영역에 포함되는가? 포함된다

(2) printf() 함수 내에 선언된 지역 변수들은 프로세스의 어느 영역에 포함되는가? 스택 영역

(3) printf() 함수의 코드와 지역 변수들은 사용자 공간에 적재되는가, 커널 공간에 적재되는가? 사용자 공간에 적재된다.

 

13. 프로세스의 주소 공간은 0번지부터 시작되어 연속적인 번지로 이루어진다. 만일 3개의 프로세스가 메모리에 적재된채 동시에 실행된다고 하면, 모든 프로세스가 0번지에서 시작하므로, 프로세스들 사이에 번지 충돌이 발생하고 메모리 충돌이 발생할 것 같다. 운영체제는 어떻게 이 문제를 해결하는가?

매핑테이블을 이용해 가상 메모리와 물리 메모리를 연결해 관리한다

 

14. 프로세스 스케줄링에는 어떤 상태의 프로세스들이 대상이 되는가?

Ready 상태

 

15. 커널은 현재 실행 중인 프로세스가 입출력을 요청하면 어떤 상태로 전이시키는가?

Blocked 상태

 

16. 프로세스는 실행 중 다음 각 경우에 어떤 상태로 바뀌는가?

(1) yield() 시스템 호출을 불러 스스로 실행을 중단하고 다른 프로세스에게 양보할 때 : Ready 상태

(2) sleep(1) 시스템 호출을 불러 1초 동안 잠을 잘 때 : Blocked 상태

(3) exit(-1) 시스템 호출을 불러 종료할 때 : Terminated/out 상태

(4) 프로세스에게 할당된 타임 슬라이스가 다 되었을때 : Ready 상태

 

17. PCB 내에 프로레스가 열어 놓은 파일에 관한 정보가 저장되는 것으로 미루어 다음 중 틀리게 설명한 것은?

한 프로세스가 열어 놓은 파일을 다른 프로세스가 입출력할 수 있다

 

18. 다음 중 자식 프로세스를 생성하는데 사용되는 시스템 호출은?

fork()

 

19. wait() 시스템 호출에 대해 잘 설명한 것은?

자식 프로세스가 종료할 때까지 대기한다

 

20. 부모 프로세스가 wait() 시스템 호출을 부르기 전, 자식 프로세스가 먼저 종료할 때 상황에 맞게 설명된 것은?

커널은 자식 프로세스를 좀비 프로세스로 만든다

 

21. 좀비 상태의 프로세스에 대한 설명 중 틀린 것은?

좀비 프로세스는 시스템의 성능을 심각하게 떨어뜨린다

 

22. 유닉스 계열의 운영체제에서 #1 프로세스를 무엇이라고 부르는가?

swapper

 

23. 유닉스 계열의 운영체제에서 모든 사용자 프로세스의 조상은 누구인가?

#1 init 프로세스

 

24. Windows에서 #0 프로세스인 시스템 유휴 프로세스(system idle process)나 리눅스의 #0 idle 프로세스의 역할은 무엇인가?

모든 프로세스가 블록 상태여서 시스템에 실행시킬 Ready 상태의 프로세스가 1개도 없는 상황에 빠지지 않도록 하기 위해서이다

 

25. 다음은 어떤 프로세스를 설명하는지 적어라.

(1) 부모 프로세스가 먼저 종료한 자식 프로세스 : 고아 프로세스

(2) 종료할 때 종료코드를 남겨 놓았지만 부모 프로세스가 읽어가지 않고 있을 때, 종료한 자식 프로세스 : 좀비 프로세스

(3) 입출력 작업이 계산 작업보다 월등히 많은 프로세스 : I/O 집중 프로세스

(4) 계산 작업이 입출력 작업보다 월등히 많은 프로세스 : CPU 집중 프로세스

(5) 사용자와 대화가 필요하지 않고 낮는 우선순위로 실행되는 프로세스 : 백그라운드 프로세스

 

26. 시스템에 무한히 많은 프로세스가 생성되지 못하는 이유가 구체적으로 무엇일까?

시스템에 과부하가 올 수도 있고 최악의 경우 너무 많은 프로세스가 존재하면 새로운 프로세스를 생성할 수 없는경우도 발생할 수 있기 때문이다

 

27. main()에서3을 리턴하는 three라는 C 프로그램을 작성하였다. 쉘에서 다음과 같이 실행시키면, main()에서 리턴한 값 3은 누구에게 전달되는가?

$ ./three
$

 

28. 종료코드의 목적은 무엇인가?

프로세스가 어떤 상태로 종료함을 부모 프로세스에게 전달하기 위해

 

[복합문제]

 

1. 다음 C 프로그램을 실행하면 오류가 발생하지는 않는다. 하지만 잘못 작성되었다고 의심되는 부분이 있다. 이를 지적하고 이유를 설명하라.

#include <stdio.h>

int main(){
   printf("I am a child\n");
   return 300;
}

return 0 을 해야 올바르게 종료를 한다. 종료코드는 0이기 때문이다.

 

※[2~3] 다음 C 프로그램에 대해 물음에 답하라. 헤더 파일은 생략하였다.

int a=10;
int main(){
	int b=20;
    int* p = (int*)malloc(100);
    f();
    printf("%d",b)
    return -1;
}
void f(){
	int c=30;
    printf("%d",c);
}

2. main() 함수의 return -1; 에서 -1을 무엇이라고 부르는가? exit(-1)로 해도 같은 의미인가? 누구에게 전달하려고 리턴하나? 이 값을 받은 프로그램이 받은 값을 양수로 출력하면 얼마가 출력될 것인가?

main() 함수의 return -1; 에서 -1은 종료코드이다.

exit(-1)해도 같은 의미이다.

부모 프로세스에게 전달하기위해 리턴한다.

양수로 출력하려면 255이다.

종료코드는 0~255(1바이트)의 값만 가능하다. 그러므로 -1은 0xff이므로 이것은 곧 양의 정수로 255이다. 결과적으로 255가 전달된다.

 

3. main() 함수가 실행되어 f() 함수 내 printf()가 실행되기 직전과 f()에서 리턴한 직후의 사용자 주소 공간을 각각 그리되, 주소 공간이 형성되는 과정과 주소 공간의 각 영역에 어떤 것들이 존재하는지 자세히 그려라. 현재 소스코드에 보이는 것들만 고려하라.

 

f() 함수 내 printf()가 실행되기 직전의 사용자 주소 공간

[코드영역]
main() 함수코드
f() 함수 코드
print()함수코드
malloc() 함수코드
[데이터 영역]
a = 10
[힙 영역]
100바이트
[미 할당 영역]
[스택 영역]
b = 20
c = 30
p = 힙 영역의 가상 주소

f()에서 리턴한 직후의 사용자 주소 공간

[코드영역]
main() 함수코드
f() 함수 코드
print()함수코드
malloc() 함수코드
[데이터 영역]
a = 10
[힙 영역]
100바이트
[미 할당 영역]
[스택 영역]
b = 20
p = 힙 영역의 가상 주소

4. 다음 C 프로그램에서 main()이 실행되면 f(2)를 호출하고, f()는 다시 g()를 호출한다. f()가 g()를 호출하기 직전과 g()에서 리턴한 직후의 사용자 주소 공간을 각각 그리되, 주소 공간이 형성되는 과정과 주소 공간의 각 영역에 어떤 것들이 존재하는지 자세히 그려라. 현재 소스 코드에 보이는 것들만 고려하라.

int a[100];
int main(){
	int b=1;
    f(2);
    return 0;
    }
void f(int c){
	int d=3;
    g();
    printf("%d",c);
}
void g(){
	int* p = (int*)malloc(100);
}

f()가 g()를 호출하기 직전의 사용자 주소 공간

[코드영역]
main() 함수코드
f() 함수 코드
print()함수코드
malloc() 함수코드
[데이터 영역]
a [100]
[힙 영역]
[미 할당 영역]
[스택 영역]
b = 1
c = 2
d = 3

g()에서 리턴한 직후의 사용자 주소 공간

[코드영역]
main() 함수코드
f() 함수 코드
print()함수코드
malloc() 함수코드
[데이터 영역]
a[100]
[힙 영역]
100바이트
[미 할당 영역]
[스택 영역]
b = 1
c = 2
d = 3

p = 힙 영역의 가상 주소

 

5. 다음 코드에 답하라.

/*************************
소스 프로그램 prac3_5.c
컴파일 및 실행 방법
$ gcc -o prac3_5 prac3_5.c
$ ./prac3_5
*************************/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>

int main(void){
    pid_t pid;
    int status;
    
    pid = fork();
    if(pid>0){ // (a) 1.부모 2.자식 3.오류처리
        sleep(2);
        wait(&status);
        printf("%d\n",WEXITSTATUS(status));
        return 0;
        }
        else if(pid==0){ // (b) 1.부모 2.자식 3.오류처리
        	sleep(1);
            return -1;
        }
        else{ // (c) 1.부모 2.자식 3.오류처리
          sleep(3);
          return 1;
       }
}

(1) 위 코드의 3개의 주석문 (a), (b), (c)에서 1.부모 2.자식 3.오류처리 중 적합한 것 하나를 선택하라

(a) 부모 (b) 자식 (c) 오류처리

(2) 실행 결과 출력되는 내용은 무엇인가? 프로그램을 실행시켜 결과를 확인하라.

(3) 자식 프로세스는 종료 후 얼마의 시간 동안 좀비 프로세스로 있게 되는가? 1초

 

6. 다음 C 프로그램에 대해 답하라.

 

/*******************************
소스 프로그램 prac3_6.c
컴파일 및 실행 방법
$ gcc -o prac3_6 prac3_6.c
$ ./prac3_6
*******************************/
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>

int main(void){
	pid_t pid;
	int status;
    
    pid = fork();
    if(pid>0){
    sleep(1);
    return 0;
    }
    else if(pid == 0){
    	sleep(2);
        printf("부모프로세스의 pid = %d", getpid());
        return -1;
    }
}

(1) fork() 후 어느 부분이 부모 프로세스의 코드와 자식 프로세스의 코드인가?

if(pid>0) 부분이 부모 프로세스의 코드이고

else if(pid==0) 부분이 자식 프로세스의 코드이다

(2) 고아 프로세스가 발생하는가? 발생한다

(3) 이 프로그램의 실형 결과는 무엇이라고 예측되는가? 프로그램을 실행시켜 결과를 확인하고 실행 결과에 대한 이유를 설명하라.

고아 프로세스가 되어도 종료 되지 않고 #1 init 프로세스에 입양된다. 그래도 여전히 고아 프로세스 라고 부른다

 

7. 1에서 10까지 더한 합을 종료코드로 리턴하는 sum.c 프로그램을 작성하라. 그리고 execlp("./sum", "./sum", NULL); 을 이용하여 sum 프로그램을 자식 프로세스로 실행시키고 종료코드를 받아 합을 출력하는 프로그램 prac3_7.c를 작성하라. 컴파일 및 실행 사례는 다음과 같다.

$ gcc -o sum sum.c
$ gcc -o prac3_7 prac3_7.c
$ ./prac3_7
1에서 10까지 합한 결과는 55
$
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
	int sum = 0;
	for (int i = 1; i <= 10; i++) {
		sum += i;
	}
	printf("1에서10까지 합한 결과는 %d",sum);
}
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
	pid_t pid;
	pid = fork(); // 자식 프로세스 생성
	if (pid > 0) { // 부모 프로세스 코드
		wait(NULL); // 자식프로세스가 종료할 때까지 대기 
		return 0;
	}
	else if (pid == 0) { // 자식 프로세스 코드
		execlp("./sum", "./sum", NULL); 
	}
	else { // fork() 오류
		printf("fork 오류");
		return 0;
	}
}

8. 다음과 같이 주어진 응용프로그램을 작성하라.

부모 프로세스는 두 변수 n과 m을 통해 자식 프로세스가 더할 범위를 지정한다. n에는 1, m에는 100을 저장한다. 이들을 전역 변수로 선언하든 지역 변수로 선언하든 상관없다. 그리고 fork()를 이용하여 자식 프로세스를 생성한다.

자식 프로세스는 부모 프로세스를 그대로 복사하므로 부모에 선언된 변수 n과 m을 그대로 물려받는다. 자식 프로세스는 변수 n에서 변수 m까지 합을 구하고 합이 1000보다 작으면 0을, 1000이면 1을, 1000보다 크면 2를 종료코드로 리턴한다.

부모 프로세스는 wait() 함수를 호출하여 자식 프로세스가 종료하기를 기다린 후, 자식 프로세스의 종료코드를 읽어 n에서 m까지의 합이 1000보다 큰 것이었는지를 판별한다.

이 프로그램이 prac3_8.c 라고할 때, 컴파일 및 실행 사례는 다음과 같다.

$ gcc -o prac3_8 prac3_8.c
$ ./prac3_8
자식 프로세스 : 10에서 100까지의 합은 5050
부모 프로세스 : 1000보다 크다.

참고로, 실행 결과에서 "자식 프로세스 : 10에서 100까지의 합은 5050"은 자식 프로세스가 출력한 것이고, "부모 프로세스 : 1000보다 크다." 는 부모 프로세스가 자식의 종료코드를 분석하여 출력한 결과이다.

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main() {
	pid_t pid;
	int child_pid;
	int n=1,m=10,sum=0;
	int status;
	

	pid = fork(); // 자식프로세스 생성 
	child_pid = wait(&status);
	if (pid > 0) { // 부모 프로세스에 의해 실행되는 코드  
		wait(NULL); // 자식프로세스가 종료할 때까지 대기
		if (WEXITSTATUS(status) == 2) {
			printf("부모 프로세스 : 1000보다 크다.\n");
		}
		else if (WEXITSTATUS(status) ==0) {
			printf("부모 프로세스 : 1000보다 작다.\n");
		}
		else if (WEXITSTATUS(status) == 1) {
			printf("부모 프로세스 : 1000이다.\n");
		}
		return 0;
	}
	else if (pid == 0) { // 자식 프로세스에 의해 실행되는 코드  
		sum = 0;
		for (n; n<=m; n++)
			sum += n;
		printf("자식프로세스: 1에서 100까지의 합은 %d\n",sum);
		if (sum < 1000) {
			return 0;
		}
		else if (sum == 1000) {
			return 1;
		}
		else if (sum > 1000) {
			return 2;
		}
	}
	else { // fork() 오류 
		printf("fork 오류");
		return 0;
	}
}

파이참은 파이썬과 장고개발에 도움을 주는 통합개발환경이다. 

https://www.jetbrains.com/ko-kr/pycharm/download/#section=mac

 

다운로드 PyCharm: JetBrains가 만든 전문 개발자용 Python IDE

 

www.jetbrains.com

사이트에 들어가 자신의 환경에 맞는 dmg 파일을 다운로드하여 설치하면 된다. 어떤 dmg 파일을 설치해야하는지 모르겠다면

터미널에 uname -p 명령어를 실행하면 된다.i386 또는 x86_64라고 출력되면 intel을 다운로드하면되고 arm64가 출력되면 apple silicon 을 다운로드하면 된다.

우 상단에 open버튼을 눌러 프로젝트를 선택한다

open 을 눌러 앞서 생성한 장고 프로젝트인 /Users/<사용자명>/projects/mysite 를 선택한다.

실행된 모습이다

파이참으로 장고 프로젝트를 불러온후 먼저 프로젝트가 바라봐야할 파이썬 인터프리터 위치를 설정해야한다.

PyCharm -> preferences 를 선택하자 

사진에 나온메뉴로 들어가자

우 상단에 Add interpreter를 눌러 add local interpreter 를 선택하자.

add local interpreter 를 누른모습

Virtualenv Environment탭에서 New 를 선택후 Base interpreter 탭에 ... 을 눌러 /Users/<사용자명>/venvs/mysite/bin/python 을 선택한후 모두 OK를 눌러 설정을 마친다.

설정을 모두 한후 맛보기로 설정값들을 수정해보자

왼쪽탭에 settings.py 를 더블클릭한 화면이다

settings.py 파일을 열어 아래로 내려보면 LANGUAGE_CODE 를 사진과 같이 'ko-kr', TIME_ZONE 을 'Asia/Seoul' 로 수정한후 서버를 다시 구동해보자. 파이참 맨 아래 탭에 Terminal 버튼을 클릭하면 Terminal을 열수있다. 사진과 같이 터미널에서 가상환경으로 진입후 

python manage.py runserver

를 실행하면 서버가 다시 구동된다.

이전과 다르게 한글로 나오는 모습

한글로 변경된다면 성공이다.

'Django > 따라하는 장고' 카테고리의 다른 글

5. 장고 모델 작성법  (0) 2022.10.13
4. 파이참의 기본 요소  (0) 2022.10.12
2. 장고 프로젝트 생성  (0) 2022.10.11
1. 파이썬과 장고설치  (1) 2022.10.10
0. 따라하는 장고  (0) 2022.10.10

장고 프로젝트를 생성하기위해 projects 라는 폴더를 만든다.

stdiohan@stdiohan-MacBookPro  ~ % mkdir projects
stdiohan@stdiohan-MacBookPro bin % source activate
(mysite) stdiohan@stdiohan-MacBookPro bin % cd
(mysite) stdiohan@stdiohan-MacBookPro ~ % cd projects 
(mysite) stdiohan@stdiohan-MacBookPro projects % mkdir mysite
(mysite) stdiohan@stdiohan-MacBookPro projects % cd mysite
(mysite) stdiohan@stdiohan-MacBookPro mysite % django-admin startproject config .

projects폴더를 만든후 가상환경을 실행한후 다시 projects 폴더로 가서 가상환경에 mysite 폴더를 새로 만들어준다. 그 후 django-admin startproject config . 명령어를 실행해 프로젝트를 생성한다.

(mysite) stdiohan@stdiohan-MacBookPro mysite % python manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
October 10, 2022 - 15:27:00
Django version 4.0.3, using settings 'config.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

python manage.py runserver 명령어를 실행해 mysite를 구동한다. 마지막 줄에 장고서버가  http://127.0.0.1:8000/ 로 시작되었고 서버를 종료하기 위해선 CONTROL-C를 입력하라는 뜻이다. 주소창에 http://127.0.0.1:8000/ 를 검색해보자.

이 화면이 뜬다면 성공한것이다

가상환경에 진입을 편하게 하기 위해서는 홈 디렉토리의  ./zshrc 파일에 다음과 같은 alias 를 추가하면 된다고한다.

alias mysite='cd /Users/<사용자명>/projects/mysite;source  /Users/<사용자명>/venvs/mysite/bin/activate

alias 를 위와 같이 등록하면 터미널 재실행후 아무곳에서 mysite를 입력하면 가상환경으로 진입된다.

alias 는 별명을 지어주는 파일,명령어라고 볼수있다.

.zshrc 파일이 없을경우 홈 디렉토리에 nano ./zshrc 로 파일을 새로 만들어 주어야한다.명령어를 적을때 화면을 작게한채로 적게되면 강제로 줄바꿈이 되어 제대로 적용이 되지 않는 경우가있다. 강제로 줄바꿈이 되지 않게 유의하며 적어야 제대로 작동된다.

'Django > 따라하는 장고' 카테고리의 다른 글

5. 장고 모델 작성법  (0) 2022.10.13
4. 파이참의 기본 요소  (0) 2022.10.12
3. 파이참 사용하기  (0) 2022.10.11
1. 파이썬과 장고설치  (1) 2022.10.10
0. 따라하는 장고  (0) 2022.10.10

+ Recent posts