코틀린은 정적 타입 언어이다.

정적 타입이라는 것은 컴파일 시점에 변수의 타입이 결정되어있는 것을 말한다.

코틀린은 정적 타입 언어이지만, 타입추론을 지원하기 때문에 타입을 명시하지 않고도 사용할 수 있다.

val greet = "hello"

println(greet) // hello
println(greet::class) // class kotlin.String
println(greet.javaClass) // class java.lang.String

greet = 0
  • 타입 추론은 컴파일 시간에 변수 초기화 시, 타입을 추론한다.
    • greet은 문자열로 초기화가 되어 String타입으로 추론되었다.
    • 다른 타입을 할당하면, 컴파일 오류가 난다.
      • 애초에 val 이기 때문에 재할당이 불가능한 것도 있다.
  • greet::class, greet.javaClass는 실행시간에 참조된 객체의 타입을 나타낸다.
    • greet::class는 참조되고 있는 객체의 코틀린 클래스를 나타낸다.
    • greet.javaClass는 참조되고 있는 객체의 자바 클래스를 나타낸다.

'Programming > 언어' 카테고리의 다른 글

[Kotlin] Collection의 View  (0) 2023.02.13
[Kotlin] Unit, Any, Nothing 클래스  (0) 2023.02.12
[Kotlin] 표현식과 명령문  (0) 2023.02.12
Java 코드가 실행되는 과정  (0) 2021.12.26
Garbage Collector 찍먹하기  (0) 2021.12.26

표현식 vs 명령문

  • 표현식은 값을 반환하고, 어떤 상태도 변화시키지 않는다.
  • 명령문은 아무것도 반환하지 않으며, 상태를 변화시키거나 변수를 변하게 하고, 파일 작성, 데이터베이스 업데이트, 네트워크 요청 등의  작업을 수행한다.

Java, C#, JavaScript 등은 표현식보다는 명령문을 더 많이 가지고 있다. (if, for, try 등)

반면, Ruby, F#, Haskell, Groovy 등은 표현식을 더 많이 가지고 있다.


코틀린의 if와 try-catch 문은 표현식이다.

자바와 같이 명령문 형태로 쓸 수도 있지만, 표현식 형태로 쓰는 것이 더 좋다.

fun canVote(name: String, age: Int): String {
    var status: String
    if (age > 18) {
    	status = "yes, please vote"
	} else {
    	status = "nope, please come back"
    }
    return "$name, $status"
}
  • 먼저 명령문 형태로 쓴 코틀린을 보자.
    • 명령문은 반환값을 주지 않기 때문에 조건에 따른 결과를 얻기 위해 뮤터블 변수가 필요해졌다.

 

val status = if (age > 18) "yes, please vote" else "nope, please come back"
  • 코틀린의 if문은 표현식이기 때문에 아래와 같이 작성할 수 있다. 
    • 변수를 이뮤터블하게 사용할 수 있고, 타입추론도 사용할 수 있다.

 

fun tryExpr(blowup: Boolean): Int {
	return try {
    	if (blowup) {
        	throw RuntimeException("fail")
        }
        2
    } catch (e: Exception) {
    	4
    }
}
  • try-catch 도 표현식으로 사용할 수 있다.
    • try문, catch문의 마지막 부분이 반환값이 된다.

a = b = c // error
  • Java는 할당을 표현식으로 취급하지만, 코틀린은 아니다.
  • 코틀린은 델리게이션(delegation)을 통해 변수를 get하거나 set하기 때문이다.
    • 추후 포스팅 예정

'Programming > 언어' 카테고리의 다른 글

[Kotlin] Unit, Any, Nothing 클래스  (0) 2023.02.12
[Kotlin] 타입추론  (0) 2023.02.12
Java 코드가 실행되는 과정  (0) 2021.12.26
Garbage Collector 찍먹하기  (0) 2021.12.26
객체지향에서 인터페이스란?  (0) 2021.12.26

PCB

Process Control Block

프로세스에 대한 정보를 담고있는 블럭으로 메모리 상에 위치한다.

각 프로세스마다 PCB가 존재하면 다음과 같은 정보를 포함하고 있다. 

  • 프로세스 상태
  • 프로그램 카운터
  • CPU 레지스터들
  • CPU 스케줄링 정보
  • 메모리 관리 정보
  • 회계 정보
  • 입출력 상태 정보

Context Switch

CPU 코어에서 작업하는 프로세스(태스크)를 교환하는 작업을 말한다.

이 과정에서 원래 실행하고 있던 프로세스의 데이터(Context)를 저장하고, 새로 실행할 프로세스의 Context를 불러온다.

이 Context가 PCB에 포함되어있다.

Context Switching은 PCB를 저장하고 불러오는 과정이다. 

 

CPU Scheduling

하나의 코어에서는 하나의 프로세스만 실행될 수 있다. 

여러 개의 프로세스 중에 CPU 코어에서 실행될 하나의 프로세스를 선택하는 것이 스케줄링이다.

스케줄링 큐

프로세스가 시스템에 들어가면, 준비 큐로 들어간다.

준비 큐에서 실행되기를 기다린다.

준비 큐에 저장되는 것은 프로세스에 대한 PCB이다.

준비 큐의 헤더는 첫 번째 PCB를 가리키는 포인터가 있다. 각 PCB는 다음 PCB를 가리키는 포인터를 포함하고 있다.

준비 큐에서 대기하다가 CPU 코어에서 실행된 프로세스는 실행이 종료되거나 대기 큐에 들어간다. 

대기 큐에 들어가는 경우는 다음과 같다.

  • 입출력
  • 자식 프로세스 생성
  • 인터럽트

대기 큐에서 각 이벤트를 처리하고 준비 큐로 다시 들어가게 된다. 

타임슬라이스가 만료된 프로세스는 바로 준비큐로 빠진다.

IPC

Interprocess Communication; 프로세스 간 통신을 말한다.

프로세스가 실행 중이 다른 프로세스들과 영향을 주고받는 다면 협력적인 프로세스라고 한다.

프로세스 협력의 장점은 다음과 같다. 

  • 정보 공유
  • 계산 가속화
  • 모듈성

자세한거는 생략

 

협력적인 프로세스들은 데이터를 교환할 수 있는 기법(IPC)이 필요하다. 

공유 메모리(shared memory), 메세지 전달(message passing) 두 가지 기법이 있다.

속도는 공유메모리 방식이 더 빠르다. 

메세지 전달은 시스템 콜을 사용하므로, 커널 간섭 등 추가적인 시간 소모가 생기지만, 공유 메모리 시스템은 공유 메모리 영역을 구축할 때만 시스템 콜이 필요하기 때문에 더 빠르다.

IPC in Shared Memory Systems

통신하는 프로세스들이 공유하는 메모리 공간을 만드는 것이다. 

프로세스들은 공유공간에 읽고 씀으로써 정보를 교환할 수 있다. 

데이터 형식과 위치는 프로세스들의 책임이다. 동일한 위치에 쓰지 않도록 운영체제가 관리해주는 것이 아니다. 프로세스들이 책임져야한다. 

IPC in Message Passing Systems

운영체제가 메세지 전달 설비를 통해서 프로세스 간에 통신을 가능하게 해주는 방법이다.

메세지 전달 시스템은 최소 2가지의 연산이 필요하다.

`send(msg)`

`receive(msg)`

두 프로세스가 통신을 하려면, 서로 메세지를 보내고 받아야한다. 

두 프로세스 간의 communication link가 있어야한다. 

  • 직접통신
    • 대칭성
    • 비대칭성
  • 간접통신
    • 메일박스

직접 통신 - 대칭성

서로의 프로세스를 가리키는 이름이 있음

`send(P, msg)` - 프로세스 P에 메세지 전송

`receive(Q, msg)` - 프로세스 Q로부터 메세지 수신

  • 두 프로세스 쌍 사이에 연결
  • 각 쌍 사이에는 하나의 연결만 존재

sender, receiver모두 상대방의 이름을 알아야 한다.

직접통신 - 비대칭성

`send(P, message)` - 프로세스 P에 메세지 전송

`receive(id, message)` - 임의의 프로세스로부터 메세지 수신 (id: 통신을 발생시킨 프로세스? 메세지를 받는 프로세스?)

 

직접통신은 프로세스 이름을 하드코딩한다는 단점이 있다. 

 

간접통신 - 메일박스

메일박스라는 곳으로 메세지를 전송하고, 수신하는 방식이다. 

메일박스는 메세지들이 들어가고 나오는 객체라고 볼 수 있다. 

각 메일 박스마다 고유한 id값을 가진다. 

`send(A, msg)` - 메일박스 A에 메세지 전송

`receive(A, msg)` - 메일박스 A로 부터 메세지 수신

 

여러개의 프로세스가 메일박스를 공유한다면, 한 프로세스가 보낸 메세지를 누가 수신하는 가는 수신 기법에 따라 다르다.

여러 프로세스가 모두 수신하는 것이 아니다.

시스템이 임의로 선택하거나, 라운드 로빈 방식 등 여러가지 알고리듬이 사용될 수 있다.

 

메일박스는 한 프로세스에게 소유되거나 운영체제에게 소유될 수 있다.

프로세스 소유 메일박스

프로세스에게 할당된 메모리 공간에 메일박스가 존재한다. 

메일박스의 소유자(해당 프로세스)가 명확하므로 receiver와 sender를 명확히 구분할 수 있게 된다.

(메일박스의 소유자는 receiver 역할만)

운영체제 소유 메일박스

특정 프로세스에 속하지 않는다.

운영체제는 다음 기능을 제공해야한다.

  • 새로운 메일박스를 생성
  • 메일박스를 통해 메세지 send, receive
  • 메일박스 삭제

메일박스를 생성한 프로세스가 메일박스의 소유자가 돼서 유일한 receiver가 된다. 

'CS > 운영체제' 카테고리의 다른 글

파일, 파일 시스템이란?  (0) 2023.09.05

컴퓨터 내부에서 사용되는 언어체계는 "비트"이다. 

비트(bit)는 2진법을 사용한다. 이 개념은 추상적이라서 사용자, 설계자가 정의하기 나름이다.

예를 들어 비트 하나를 스위치로 생각해서 on/off 나 1이면 오후, 0이면 오전 처럼 임의로 정의해서 사용할 수 있다. 

논리 연산

비트를 참, 거짓으로 사용해서 어떤 연산을 하는 것을 말한다.

불리언 대수

조지 불이 만든 비트(참, 거짓)에 사용할 수 있는 연산 규칙이다.

NOT, AND, OR, XOR의 연산이 있다.

다 아니까 생략.

드 모르간 법칙

불리언 대수에 적용할 수 있는 추가적인 법칙이다.

논리 연산에 모든 것을 뒤집었을 때의 결과는 같다.

a AND b == NOT(NOT a OR NOT b)

https://m.blog.naver.com/mino522/220414861127

비트로 수를 표현하는 방법

인간은 10진수를 사용한다. 

각 자릿수에 0~9까지 10가지 숫자가 들어갈 수 있다.

2진수는 2를 밑으로 사용하는 체계이다. 

각 자릿수에 0~1까지 2가지 숫자가 들어간다. 

10진수 5028 == 2진수 1001110100100

10^3 10^2 10^1 10^0
5 0 2 8
2^12 2^11 2^10 2^9 2^8 2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0
1 0 0 1 1 1 0 1 0 0 1 0 0

 

  • 10진수 세기
    • 0, 1, 2, 3,... , 9, 10, 11, 12, 13,... , 99, 100, 101, 102,... , 999, 1000
  • 2진수 세기
    • 0, 1, 10, 11, 100, 101, 110, 111, 1000

 

2진수 에서 가장 오른쪽의 2^0자리 수를 LSB(최소 유효 비트)라고 부르고, 가장 왼쪽의 2^n자리 수를 MSB(최대 유효 비트)라고 부른다.

2진수 덧셈

오른쪽(LSB)에서 왼쪽(MSB)으로 더한다.

덧셈 결과와 올림수를 고려해서 계산한다.

A B 덧셈 올림수
0 0 0 0
0 1 1 0
1 0 1 0
1 1 0 1

잘 보면 덧셈 결과는 XOR이고, 올림수는 AND이다.

컴퓨터 하드웨어에서 2진수의 덧셈은 XOR과 AND를 사용해서 할 수 있다.

덧셈을 하다 보면 덧셈의 결과가 사용할 수 있는 비트의 수를 넘어가는 경우가 있다. 이를 오버플로우라고 한다. 

예를 들어 1001 + 1000 = 10001이다. 하지만 4비트만 사용할 수 있다면, 0001만 결과로 나온다.

이런 경우 조건 코드 레지스터 - 오버플로우 비트에 오버플로우가 발생했다는 정보를 담아둔다. 

반대의 경우인 언더플로우도 있다. 

음수 표현

2진법에서 뺄셈은 음수를 더한다고 할 수 있다.

2진법에서 음수를 표현하는 방법은 3가지가 있다.

부호와 크기

가장 왼쪽 비트 MSB를 부호로 사용하는 것이다.

0이면 양수, 1이면 음수 이런 식이다.

이 방식의 단점은 사용할 수 있는 수의 범위가 줄어든다는 것과 0을 표현하는 방법이 2개가 생긴다.

또 연산 결과가 부정확하다. +1 = 0001, -1 = 1001을 더하면 1010 = -2이다.

그저 표현하는 방법일 뿐이다. 복잡한 방법으로 정당화할 수 있는 방법이 있긴 하다.

1의 보수

양수의 모든 비트를 반전시킨 것을 음수로 사용하는 것이다. 

0001 = 1, 1110 = -1이다.

덧셈을 할 때는 순환 올림을 해주어야 한다. MSB의 올림 비트를 LSB에 더해주는 것이다. 

1의 보수 방법도 +-0이 중복된다는 단점이 있다.

2의 보수

양수 비트에서 더했을 때, 0이 나오는 비트 패턴을 음수라고 지정한 것이다.

모든 수를 반전시키고, 1을 더하면 음수 비트 패턴이 나온다. 

0001 = +1, 1111 = -1

0001+1111=10000 인데 오버플로우가 발생해서 0000이 결과가 나온다.

2의 보수를 사용하면 0을 표현하는 방법이 1가지 이다.

실수 표현법

고정 소수점

소수점의 위치를 정해두고 항상 일정하게 사용, 해석하는 것이다.

예를 들어 4비트 중 왼쪽 2비트를 정수부분, 오른쪽 2비트를 소수(분수)부분으로 사용한다고 가정하고 계산하는 것이다.

넓은 범위의 수를 다룰수록 사용하는 비트가 많아진다는 단점이 있어 범용 컴퓨터에서 사용하지 않는다.

부동 소수점

과학적 표기법으로 수를 표현하는 방법이다. 0.0012를 1.2*10^-3 이런식으로 표현하듯 가수부와 지수부를 나눠서 사용하는 것을 말한다.

2진법에서 지수부의 밑은 2이다.

부동소수점 방식은 비트 조합 낭비와, 모든 비트 패턴을 표현하지 못한다는 단점이 있지만, 현재 컴퓨터에서 사용하는 표준 방법이다.

추후에 따로 다루겠다.

2진수를 다루는 방법

BCD

4비트의 2진수를 사용해서 10진수를 자릿수 별로 표현하는 것이다.

12는 0001(1) 0010(2) 이렇게 표현한다.

낭비되는 비트가 많다.

8진 표현법

2진수를 3비트씩 묶어서 8진수로 변환해 사용하는 것이다.

긴 2진수를 더 짧게 읽어지도록 하는 것이다.

16진 표현법

2진수를 4비트씩 묶어서 16진수로 변환해 사용하는 것이다.

진법 표기법

  2진수 8진수 10진수 16진수
숫자 10 10 10 10 10
10진수 변환 2 8 10 16

프로그래밍 언어에서 각 진수들을 표현하는 방법

  • 0으로 시작하면 8진수
    • 017 -> 15
  • 1~9로 시작하면 10진수
  • 0x로 시작하면 16진수
    • 0x12f -> 303

비트 그룹 이름

비트 이름
4 니블
8 바이트
16 하프 워드
32 워드
64 더블 워드

텍스트 표현

  • 아스키 코드
    • 7비트
    • 영어, 숫자, 특수문자, 제어문자 등
  • 유니코드
    • 모든 언어를 포함하는 표준
    • 16비트
      • 21비트 확장

'CS > 컴퓨터구조' 카테고리의 다른 글

CPU는 어떻게 명령을 처리할까?  (1) 2023.10.22

+ Recent posts