"switch문과 if문의 차이는 무엇일까? 성능의 차이가 있을까?"


switch문과 if문의 성능에 대해서 이야기를 하는 시간을 가져보고자 합니다.

프로그래밍을 배우다 보면 선택문을 사용해야 할 때 if문을 사용하거나 switch문을 사용합니다.

물론 switch문을 쓸 수 있는 경우는 전부 if문으로 대체 가능합니다만,

if문으로 가능한 것들 중 switch문으로 구현 불가능한 경우도 있죠.


이번 포스팅에서는 switch문과 if문 모두 가능한 경우에 대해서 따져보고자 합니다.

(당연한 이야기겠죠... 두 개 동시 사용 가능한 경우에 대해서 이런 논의가 의미가 있는 것이죠)


그리고, 단순히 고수준 언어의 측면에서 보기보단 ISA의 관점에서 풀어서 포스팅을 해보고자 합니다.

따라서, 특정 고수준 언어에 대해서는 이 포스팅의 내용이 옳지 않을수도 있습니다.

왜냐하면 고수준 언어들은 더욱 복잡한 컴파일러에 귀속되어 있는데, 

그 언어의 컴파일러가 어떠한 방식으로 instruction set (혹은 기계어나 어셈블리어)를 만들어가는지는 언어마다 다르기 때문입니다.


제가 공부한 ISA인 MIPS에는 branch statement와 jump statement가 있습니다.

branch statement는 레지스터 2개를 비교해서(혹은 레지스터와 상수를 비교해서) 특정 메모리 번지로 이동할 것이냐 말것이냐?를 결정합니다. 

jump statement는 즉시 특정 메모리 번지로 이동하는 기능을 합니다.


그리고 if문은 branch statement에 기반을 두고 있고,

switch문은 jump statement에 기반을 두고 있습니다.


왜냐하면, if문은 조건이 만족하면 실행/만족하지 않으면 무시 (실행을 할 것이냐 말것이냐?)

switch문은 입력된 값을 보고 특정 위치로 점프 (어떤 코드를 실행할 것이냐?)


switch문은 "점프테이블"을 만들고 switch문의 입력값으로 받은 변수 값만큼 점프 테이블 내에서 이동하면 됩니다.

if문보다 훨씬 쉽네요? 점프 테이블만 만들수 있다면 말이죠.


대충 이 정도 이야기를 하면 어느 정도 눈치를 채셨을 수도 있는데,

if-else문은 각 조건마다 그 조건 처리할수 있게 레지스터를 변경해주는 그런 인스트럭션들이 먼저 선행되야 합니다. 각 조건마다.

그런데, switch문은 점프 테이블을 만들기만 하면 조건이 몇개든 훨씬 빠르고 쉽게 넘어갈 수 있어요.

다만 점프 테이블을 만드는 오버헤드가 있는거죠.


<정리하자면>

if문

장점: 점프 테이블을 만드는 오버헤드가 없다.

단점: if 혹은 else if를 만날 때마다 조건을 만족하는지 안하는지를 확인하기 위한 인스트럭션이 계속해서 필요됨.

즉, 따져야 할 조건의 수가 적을 경우 if-else를 쓰는 것이 유리함.


switch문

장점: switch문 시작시에 입력받은 값을 확인하는 인스트럭션만 필요. 조건을 확인하는 인스트럭션이 필요 없음.

단점: 점프 테이블을 만드는 오버헤드가 있음.

즉, 따져야 할 조건의 수가 많아져도 인스트럭션이 추가로 요구되는 것이 아니기 때문에,

따져야 할 조건이 많은 경우 switch문을 쓰는 것이 유리합니다.


자바 GUI (그래픽 유저 인터페이스) 프로그래밍 [1]

에 이어서 조금은 더 고급(?) 스러운 예제를 다뤄 볼까 합니다.

앞서 다룬 예제는 솔직히.. 예제랄것도 없었죠?

그냥 프레임 클래스와 패널 클래스등을 사용하여 단순히 GUI 윈도우를 띄어보는 수준에 그쳤는데요.

이번 글에서는 조금 더 나아가서 버튼을 사용하고, 버튼을 눌러서 상호작용하는 아주 간단한 예제까지 다뤄보고자 합니다.


Content Pane과 Panel에 대한 설명이 이전 포스팅에서 다 되었기 때문에 기초 지식은 다 안다고 생각합니다.

따라서, 바로 예제 코드를 보는 것이 더 좋을 것 같네요


import javax.swing.*;

import java.awt.Color;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;


public class ButtonDemo implements ActionListener {

int redScoreAmount = 0;

int blueScoreAmount = 0;

JPanel titlePanel, scorePanel, buttonPanel;

JLabel redLabel, blueLabel, redScore, blueScore;

JButton redButton, blueButton, resetButton;

public JPanel createContentPane() {

/* total panel */

JPanel totalGUI = new JPanel();

totalGUI.setLayout(null);

/* titel panel */

titlePanel = new JPanel();

titlePanel.setLayout(null);

titlePanel.setLocation(10, 0);

titlePanel.setSize(250, 30);

totalGUI.add(titlePanel);

redLabel = new JLabel("Red Team");

redLabel.setLocation(0, 0);

redLabel.setSize(100, 30);

redLabel.setHorizontalAlignment(0);

redLabel.setForeground(Color.red);

titlePanel.add(redLabel);

blueLabel = new JLabel("Blue Team");

blueLabel.setLocation(120, 0);

blueLabel.setSize(100, 30);

blueLabel.setHorizontalAlignment(0);

blueLabel.setForeground(Color.blue);

titlePanel.add(blueLabel);

/* score panel */

scorePanel = new JPanel();

scorePanel.setLayout(null);

scorePanel.setLocation(10, 40);

scorePanel.setSize(250, 30);

totalGUI.add(scorePanel);

redScore = new JLabel("0");

redScore.setLocation(0, 0);

redScore.setSize(100, 30);

redScore.setHorizontalAlignment(0);

scorePanel.add(redScore);

blueScore = new JLabel("0");

blueScore.setLocation(120, 0);

blueScore.setSize(100, 30);

blueScore.setHorizontalAlignment(0);

scorePanel.add(blueScore);

/* button panel */

buttonPanel = new JPanel();

buttonPanel.setLayout(null);

buttonPanel.setLocation(10, 80);

buttonPanel.setSize(250, 70);

totalGUI.add(buttonPanel);

redButton = new JButton("Red Score!");

redButton.setLocation(0, 0);

redButton.setSize(100, 30);

redButton.addActionListener(this);

buttonPanel.add(redButton);

blueButton = new JButton("Blue Score!");

blueButton.setLocation(120, 0);

blueButton.setSize(100, 30);

blueButton.addActionListener(this);

buttonPanel.add(blueButton);

resetButton = new JButton("Reset Score");

resetButton.setLocation(0, 40);

resetButton.setSize(220, 30);

resetButton.addActionListener(this);

buttonPanel.add(resetButton);

totalGUI.setOpaque(true);

return totalGUI;

}


private static void createAndShowGUI() {

JFrame.setDefaultLookAndFeelDecorated(true);

JFrame frame = new JFrame("[=] JButton Score! [=]");

ButtonDemo demo = new ButtonDemo();

frame.setContentPane(demo.createContentPane());

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setSize(250, 190);

frame.setVisible(true);

}

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {


@Override

public void run() {

// TODO Auto-generated method stub

createAndShowGUI();

}

});

}


@Override

public void actionPerformed(ActionEvent e) {

// TODO Auto-generated method stub

Object obj = e.getSource();

if (obj == redButton) {

++redScoreAmount;

redScore.setText("" + redScoreAmount);

} else if (obj == blueButton) {

++blueScoreAmount;

blueScore.setText("" + blueScoreAmount);

} else if (obj == resetButton) {

redScoreAmount = 0;

blueScoreAmount = 0;

redScore.setText("" + redScoreAmount);

blueScore.setText("" + blueScoreAmount);

}

}

}


결과물



코드가 갑자기 너무 방대해졌나요? 실은 큰 의미가 있는 코드들은 그닥 길지 않습니다. 찬찬히 읽어보시면 충분히 이해가 갈겁니다.

일단, 당연히 프로그램이 실행되면 main 메서드가 호출이 될 것이고, 

createAndShowGUI() 메서드를 호출하는 구문을 볼 수 있을 것입니다.

createAndShowGUI에서는 이 프레임의 ContentPane을 createContentPane 메서드로 반환하도록 하였는데요. 

그 메서드가 바로 맨 위에 길다란 메소드 구문입니다.

또, createContentPane 메서드에서 버튼 구성요소들에게는 addActionListener(this) 메서드로 액션 리스너를 설정하였는데요.

액션 리스너는 그 버튼이 클릭될 경우 actionPerformed 메서드를 호출하도록 하는 리스너입니다.


디스플레이 구성요소에는 크게 세 부분이 있는데요. 타이틀 패널, 스코어 패널, 버튼 패널이 있습니다.




많은 개발자분들이 자바 언어를 사용하시는 경우가 많을 것이라고 생각하는데요.

자바 언어를 활용하여 콘솔 창에서 다양한 프로그램을 작성해본 경험은 있어도 GUI 프로그래밍을 해본적은 없는 분들을 위해서 간단한 GUI 프로그래밍 방법에 대해서 소개해드리고자 합니다. 자바 언어를 아주 간단히 사용해본 적이 있으신 분들에 대해서 읽어보시면 좋을 듯합니다.


자바는 GUI 프로그래밍을 위해 2가지 패키지를 제공하고 있습니다.

- abstract windows kit (AWT) 

- swing toolkit

AWT가 기존의 것이고, swing toolkit이 더 새로운 것입니다. Swing 패키지에서 제공하는 프레임들은 기존 AWT가 제공하는 프레임들과 구별하기 위해서 JFrame과 같은 클래스 이름을 사용하고 있습니다. (AWT에서 제공하는 프레임 클래스는 Frame) 즉, 맨 앞에 J를 붙여줌으로써 Swing 패키지에서 제공하고 있음을 병시하는 것입니다. 


표시가능한 프레임들 JWindows, JDialog, JApplet과 같은 최상 수준의 컨테이너들이고,

표시되지 않는 컨텐츠 틀들 JPanel, JoptionsPane, JScrollPane, JSplitPane들과 같은 중간 수준의 컨테이너들입니다.

(최상 수준, 중간 수준이라는 말은 고수준-저수준의 용어의 맥락에서 생각하시면 편합니다. 수준이 높을수록 좋은게 아니고, 사람과 더 가까이 있다는 것을 의미합니다. 즉, 눈에 보이는 컨테이너들이 최상 수준이고, 눈에 보이지는 않지만 작동하고 있는 것들이 중간 수준, 혹은 저수준이라고 말할 수 있는 것이지요)


여기서 컨테이너란 위젯들을 말하거나 다른 위젯들을 관리하고 처리하는 GUI 컨트롤들을 말합니다. 

위젯들은 간단히 말해 텍스트 박스, 체크 박스, 버튼 같은 GUi 컴포넌트를 말하는 것이구요. 

(두 개가 큰 차이가 있다기 보단 위젯이 더 작은 구성요소, 그것을 그룹화하고 관리하는 것이 컨테이너라고 말할 수 있습니다.)


아래는 자바를 관리하는 썬에서 제공하는 그림입니다.



여기서 중요한 것은 위젯을 추가하여 GUI 컨트롤을 보여주려면, 그것을 Content Pane에 추가해야 한다는 것입니다.


충분히 기본적인 지식은 다 쌓았다고 생각이 듭니다.

자, 이제 다음 가장 간단한 GUI 예제를 보시면 되겠습니다.


import java.awt.*; import java.awt.event.*; import javax.swing.*;

public class Frame1 extends JFrame { JPanel pane = new JPanel(); Frame1() { super("Empty Simple Frmae"); 

setBounds(100,100,300,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Container con = this.getContentPane(); con.add(pane); // add the panel to content pane

/* customize panel here */

setVisible(true); }

public static void main(String args[])

{

Frame1 frame = new Frame1();

} }


중간 수준에서 위젯들을 그룹화하고 처리할 (물론 이 예제에서는 딱히 처리할 위젯이나 GUI 컨트롤이 없긴 하지만) JPanel 클래스를 만들어줍니다. 그리고 이 Panel을 Content Pane에 추가합니다. 그 이후, 패널을 자유자재로 설정해주시고, setVisible(true)를 호출하면 간단한 GUI 프레임이 등장하는 것을 보실 수 있으실 겁니다.

기업이나 개인이 인터넷에 독자적인 도메인 네임을 가지고 사이트를 구축하기 위해서는 수 천만원 대에서 수 백만원 대의 서버 컴퓨터를 구비하고 최소 수 십만원 대의 전용선 사용료를 매월 지불해야 한다.


웹 호스팅 서비스는 이러한 물리적인 서버 구축으로 인한 초기 비용을 없애고, 또한 전문적인 인터넷 및 네트워크 관리 지식 없이 소규모 기업 혹은 단체의 고유 도메인을 통해 다양한 정보를 제공할 수 있도록 하는 서비스이다.


즉 웹서버를 직접 구축하지 않고 웹서버 제공업체의 하드디스크 일부 공간을 빌려서 기업 및 단체들이 웹서버를 가지고 있는 것과 동일한 효과를 낼 수 있다.


이렇게 되면 네트워크와 인터넷을 직접 구축하지 않고도 웹 호스팅 서비스 제공 업체의 서버 공간을 임대해서 자체 웹서버가 없더라도 www.회사이름.com 또는 www.회사이름.co.kr을 운영할 수 있게 된다.


결국 웹 호스팅 서비스는 자체 웹 서버를 구축하기 어려운 업체나 단체를 대상으로 인터넷 홈페이지 주소를 만들어주고, 인터넷 서버를 대여해 주는 서비스로서, 웹 서버 구축을 위하여 고가의 하드웨어, 소프트웨어 그리고 전문 인력을 갖추지 않고도 전세게 어디서나 접근 가능한 자체 서버를 저럼한 비용으로 구축할 수 있으며, 아울러 독자적인 도메인 네임을 사용할 수 있다.


이러한 웹호스팅 서비스를 제공하는 업체를 WSP(Web hosting Service Provider)라고 하며, 국내에도 많은 업체들이 있다. 이들 업체들은 매우 다양한 형태로 서비스를 제공하기 때문에 웹 호스팅을 하기 위해서는 WSP의 사용료, 서비스 종류 등을 면밀히 비교, 검토하여 선택하는 것이 바람직하다.

서버 구축시 중요한 점은 IP의 설정이다. 이 IP는 인터넷을 사용하는 데 있어 서버와 클라이언트에 반드시 배정되어야 한다. 서버 측면에서는 이 IP가 설정되어 있어야 정보를 요구하는 클라이언트의 접속을 허용하게 할 수 있고, 클라이언트 측면에서는 IP가 배정되어 있어야 서버에 정보를 요구할 수 있는 것이다. 도메인 네임은 이러한 IP를 사람이 쉽게 기억할 수 없기 때문에 단지 영문자로 표시하는 형태이기 때문에 해당 IP와 대응되는 것일 뿐이다. 즉 인터넷에 연결된 컴퓨터들은 도메인 네임은 없을 수 있으나, IP는 반드시 있어야 한다. 즉, 인터넷에 연결하고자 하는 모든 컴퓨터들은 IP가 반드시 배정되어 있어야 한다.


그러나 현재 인터넷에 연결하고자 하는 IP의 개수는 어느 정도 한정되어 있다. 특히 LAN을 통해 인터넷에 연결되는 컴퓨터를 제외하고 PPP를 통해 인터넷에 연결되는 컴퓨터에 IP를 배정하는 데 있어서 한 가지 유의해야 할 점이 있다.


IP를 배정하는 데 있어서 접속할 때마다 항상 동일한 IP가 설정되는 정적(static) IP와 접속할 때마다 다른 IP가 설정되는 동적(dynamic) IP가 있다.


ISP에 가입하여 인터넷을 사용하는 데 있어서, 가입자들이 동시에 인터넷을 사용하는 경우는 매우 드물다. 즉 동시에 인터넷을 사용하는 경우는 약 10%정도이다. 이 경우 모든 ISP 가입자들에게 정적 IP 를 할당해주게 되면, 사용하지도 않는 IP가 낭비되는 셈이다. 따라서 각 ISP는 PPP를 통해 인터넷에 접속하는 컴퓨터에 접속할 때마다 다른 IP를 즉, 현재 사용 가능한 IP를 수시로 변경하여 배정하게 된다. 이것이 바로 동적 IP이다. 이런 동적 IP들을 따로 모아두고 있는 것을 IP 풀(pool)이라고 한다. 이렇게 관리하게 되면 IP 개수를 낭비하지 않게 된다.


정리하면, PPP를 통해 인터넷에 접속하게 되면 ISP시스템에서는 IP 풀에 사용가능한 IP 를 접속하고자 하는 컴퓨터에 배정하는 과정을 통해 인터넷을 사용하게 된다. 이것이 바로 동적 IP를 배정하는 과정인 것이다.


따라서 PPP를 통해 서버를 구축하고자 할 경우에 IP가 수시로 변경되므로 인터넷에 접속시 할당되는 IP를 잘 파악하여 설정하여야 한다.

<프로세스 동기화 내용 목차>

1. Critical-Section Problem (임계 영역 문제)

2. Hardware Synchronization (하드웨어 동기화)

3. Semaphore (세마포어 - 소프트웨어 동기화)

4. Classic Problems of Synchronization (동기화의 고전문제들)

5. Monitors (모니터)



Q. 임계 영역이란 무엇인가? 임계 영역 문제란 무엇인가?

 임계 영역은 공유 데이터에 접근하는 코드이다. 공유 데이터에 동시 접근하게 되면 데이터의 무결성이 손상될 수 있다. 이러한 문제가 바로 임계 영역 문제이다. 임계 영역 문제은 생산자-소비자 문제라고도 한다. 생산자, 소비자 역할을 하는 프로세스 2개가 동시에 공유 자원에 접근함으로써 기대했던 값과는 다른 결과가 나오게 된다. (그리고 이러한 상황을 경쟁조건이라고도 한다.)



Q. 경쟁 조건이란 무엇인가?

 경쟁 조건(race condition)이란 임계영역의 부적절한 처리로 예상치 못한 결과를 발생시킬 수 있는 상황을 의미한다. 경쟁 조건 문제를 해소하려면 반드시 한 순간에 하나의 프로세스만 임계영역을 실행할 수 있도록 보장해야 한다.



Q. 임계 영역 문제의 해결책이 되기 위한 조건은 무엇이 있나? (특정 해결책(solution)이 임계 영역 문제를 해결한다고 말하려면 무슨 조건을 만족해야 하나?)

 임계 영역 문제의 해결책이 되려면 3가지 조건을 만족해야 한다. 상호 배제(Mutual Exclusion), 진행(Progress), 한정 대기(Bounded Waiting)이다.

1 .프로세스 Pi가 임계영역에 존재하는 경우, 다른 프로세스는 임계영역을 실행하지 못하도록 하면 상호 배제 조건을 만족한다고 할 수 있다. 

2. 임계 영역 안에서 실행하고 있는 프로세스가 없는 경우, 임계 영역을 실행하고자 하는 프로세스는 반드시 임계 영역을 실행할 수 있어야 한다. 이를 만족하면 진행 조건을 만족한다고 할 수 있다. 

3. 임계 영역을 요청한 프로세스는 무한히 대기하면 안된다. 즉, 제한된 대기 시간을 가져야 한다. 이를 만족하면 한정 대기 조건을 만족한다고 할 수 있다.

 3가지 조건을 모두 만족해야만 임계 영역 문제(critical section problem)을 해결할 수 있는 해결책(solution)이라고 할 수 있다.



Q. 임계 영역 문제 해결책에는 어떠한 것이 있는가?

 임계 영역 문제 해결책은 임계영역의 실행여부를 알 수 있는 메커니즘이 제공되는지가 관건이다. 임계 영역 문제 해결책으로는 크게 하드웨어적 해결책과 소프트웨어적 해결책이 있다. 하드웨어적 해결책으로는 TestAndSet, Swap 등이 있고, 소프트웨어적 해결책으로는 세마포어, 모니터, 조건 변수 등이 있다.



Q. TestAndSet의 작동방식을 설명하라.

boolean * TestAndSet (boolean * target) 

{

  boolean * rv = * target;

  *target = TRUE;

  return rv;

}


인자로 받은 값을 그대로 반환한다. 다만, 인자의 값자체를 TRUE로 변경한다.


while(true) 

{

  while(TestAndSet(&lock))

    ; // do nothing

  // critical section

  lock = FALSE;

  // remainder section

}


제일 처음에는 lock은 FALSE값으로 초기화되어 있다. 따라서, 처음으로 실행한 프로세스는 첫 while문을 통과한다. 그리고, TestAndSet에 의해서 lock은 TRUE가 되었으므로, 다른 프로세스가 임계 영역을 실행하려고 해도, while문에서 걸려서 실행할 수 없다. 상호 배제 조건을 만족하는 셈이다. 그리고 임계 영역을 다 끝낸 프로세스는 lock값을 다시 FALSE로 되돌려서 다른 프로세스도 임계영역을 실행할 수 있도록 한다. 따라서, 진행 조건도 만족하는 셈이다.

다만, 한정 대기 조건을 만족한다고 볼 수는 없다.



Q. Swap 의 작동방식을 설명하라.

void Swap (boolean *a, boolean *b)

{

  boolean temp = *a;

  *a = *b;

  *b = temp;

}


인자로 받은 a,b의 값을 서로 바꾼다.


while(true)

{

  key = TRUE;

  while ( key == TRUE)

    Swap(&lock, &key);

  // critical section

  lock = FALSE;

  // remainder section

}


제일 처음에는 lock값이 FALSE로 초기화되어있다. 따라서, lock과 key를 swap하면 key 값이 FALSE가 되어 바로 while문을 통과한다. 하지만, lock값이 TRUE가 되었으므로 다른 프로세스는 while문을 빠져나가지 못한다. 즉, 상호 배제 조건을 만족하는 셈이다. 그리고 임계 영역을 다 진행한 프로세스는 lock값을 FALSE로 되돌리므로 다른 프로세스도 임계 영역을 실행할 수 있또록 한다. 따라서, 진행 조건도 만족하는 셈이다.

다만, 한정 대기 조건을 만족한다고 볼 수는 없다.



Q. 한정 대기 조건을 만족하도록 TestAndSet 을 사용하여 임계영역을 구현하라.

우선, boolean waiting[n]; boolean lock;을 공유 변수(전역 변수)로 선언한다. waiting 배열을 이용하여 한정 대기 조건을 만족하도록 구현할 것이다.


do

{

  waiting[i] = TRUE;

  key = TRUE;

  while(key && waiting[i])

    key = TestAndSet(&lock);

  waiting[i] = FALSE;

  // critical section

  j = (i+1)%n;

  while((j!=i) && !waiting[j]) // scanning in 'waiting'

    j = (j+1)%n;

  if(j==i)             // if no process is waiting

    lock = FALSE; // lock release

  else                          // if a waiting process exists

    waiting[j] = FALSE; // the process can enter the critical section in next order.

} while (TRUE);


처음에 lock값은 FALSE로 초기화되어 있다. 처음으로 임계영역에 들어가는 프로세스에서는 TestAndSet에 의해서 key가 FALSE가 된다. 따라서 바로 while문을 통과하여 임계 영역을 진행한다. 이때, lock은 TestAndSet에 의해서 TRUE가 되었으므로 key값은 계속해서 TRUE이고, 다른 프로세스는 while문을 통과하지 못한다. 따라서, 상호 배제 조건을 만족한다고 할 수 있다. 


그 다음, 임계 영역을 모두 진행한 프로세스는 waiting 배열을 i+1, i+2, ... , n-1, 0, ... i-1 순서대로 조사한다. 조사한 순서에서 가장 처음으로 waiting값이 TRUE인 프로세스를 찾으면, 그 프로세스가 다음 차례로 임계 영역을 실행하는 프로세스가 된다. 그리고 만약 모두 조사했음에도 waiting값이 TRUE인 프로세스가 없다면 완전히 lock을 FALSE로 돌려버린다. (즉, lock을 놓아버린다.) 즉, 임계영역에 들어가기를 원하는 모든 프로세스들이 최대한 n-1 번 안에는 임계영역에 들어갈 수 있게 된다. 한정 대기 조건을 만족하게 되었다. 또한, 기다리는 프로세스가 없는 경우는 당연히 lock이 FALSE값이 되므로 바로 프로세스가 임계영역에 들어갈 수 있다. 진행 조건도 만족한다.

따라서, 위 구현은 3가지 조건을 모두 만족하므로 임계 영역을 완벽하게 해결한다.



Q. 세마포어란 무엇인가? 어떻게 구현하나?

 세마포어는 소프트웨어적 프로세스 동기화 기법 중 하나다. 세마포어 변수값에는 wait, signal 라고 하는 원자적 명령에 의해서만 접근이 가능하다. (원자적 명령이라는 말은 그 명령 혹은 함수가 진행하는 동안 다른 방해가 들어오지 않음을 의미한다.)


wait (S) {

  while S<=0

    ; // no-op

  S --;

}

signal (S) {

  S ++;

}


이러한 구현을 한 세마포어(무한루프로 wait을 구현한 세마포어)를 spin lock(스핀 락)이라고도 한다. 스핀 락은 불필요한 CPU 싸이클을 낭비하므로 좋지 못한 구현이다. (물론 스핀 락도 유일한 장점을 가진다. 바로, 컨텍스트 스위치가 전혀 없다는 것이다.) 따라서, 대기 큐를 이용한 세마포어 wait, signal 구현도 가능하다. 다만, 그러한 구현은 새로운 문제인 데드락을 발생시킨다.


wait (S) {

  S --;

  if ( S < 0 )

  {

    add this process to Waiting Queue;

    block;

  }

}

signal (S) {

  S ++;

  if( S >= 0 )

  {

    remove the process 'P' from Waiting Queue;

    wakeup (P);

  }

}



Q. 데드락, 교착 상태란 무엇인가?

 교착 상태를 쉽게 표현하면 '모든 것이 모든 것을 막는다'라는 상황이다. 세마포어를 waiting queue 를 이용해서 구현하면 2개 이상의 프로세스가 영원히 기다리는 상황이 발생할 수도 있다. wait 함수를 호출해 기다리는 상태에서 그에 상응하는 signal 액션이 영원히 발생하지 않는 상황이 되면, 그러한 상황에 있는 프로세스을 교착상태에 빠졌다고 말한다. 예를 들어 다음과 같은 프로세스가 2개 있으면 P0, P1 이 교착상태에 빠지게 된다. 세마포어 Q,S가 있다고 하고, 이들은 초기값을 1로 한다.


P0                  P1

wait(S);           wait(Q);

wait(Q);          wait(S);

...                   ...

signal(S);        signal(Q);

signal(Q);       signal(S);


만약, P0, P1 이 동시에 첫 줄을 실행하면 S와 Q 모두 세마포어 변수값이 0이 된다. 그 후 두번째 줄을 실행하면, S와 Q 모두 값이 0이므로 block이 된다. P0의 wait(Q)를 깨우려면 P1의 signal(Q);가 작동해야 하는데, wait(S)로 막혀 있으므로 절대 도달하지 않는다. 또한, P1의 wait(S)를 깨우려면 P0의 signal(S)가 작동해야 하는데, wait(Q)로 막혀 있으므로 절대 도달하지 않는다. 이러한 상황에 있을 때, P0, P1은 교착상태에 빠졌다고 말한다.



Q. 한정된 버퍼 문제란 무엇인가? (Bounded-Buffer Problem)



Q. 저자-독자 문제란 무엇인가? (Readers-Writers Problem)



Q. 식사하는 철학자 문제란 무엇인가? (Dining-Philosophers Problem)



Q. 모니터가 보장하지 못하는 경우에는 무엇이 있나?

총 4가지 경우가 있다. 

1. 자원에 대한 접근 권한을 얻지 않았음에도 자원에 대해 접근을 할 수도 있다. 

2. 자원에 접근하는 것에 대한 승인을 받은 후에 절대로 자원을 놓지 않을 수도 있다.

3. 요청하지 않은 자원을 놓을 수도 있다. 

4. 똑같은 자원을 두 번 요청할 수도 있다. (자원을 놓는 일을 하지 않고서도)


'컴퓨터 프로그래밍' 카테고리의 다른 글

웹 호스팅(Web Hosting)  (0) 2014.06.06
정적 IP와 동적 IP  (0) 2014.06.06
[파일처리] 저장장치와 파일구조  (0) 2014.04.19
[운영체제] CPU 스케줄러  (2) 2014.04.17
[운영체제] 쓰레드  (0) 2014.04.17

+ Recent posts