9주차 c# 과제 레포트입니다.
모든 코드는 gist(https://git.io/fjGar)에 업로드하였습니다.
쓰레드를 사용하여 실행 간격이 각기 다르게(1초, 2초, 3초) 동작하는 프로그램을 작성하는 문제입니다.
먼저 출력은 다음과 같습니다.
이 문제는 Thread
가 어떻게 동작하는지만 잘 파악하고 있으면 큰 어려움 없이 해결이 가능한 문제입니다.
[Thread에 대한 설명]
이러한 것을 구현한 코드는 다음과 같습니다.
using System;
using System.Threading;
namespace Problem_1
{
class Program
{
// global time
private static int s = 0;
// get ThreadStart instance
private static ThreadStart getThreadStart (int i) {
return new ThreadStart(() =>
{
// sub thread loop
while (true)
{
if (i == 1)
{
Console.WriteLine($"{i}번 쓰레드 {s}");
} else
{
Console.WriteLine($"{i}번 쓰레드");
}
Thread.Sleep(i * 1000);
}
});
}
static void Main(string[] args)
{
Console.WriteLine("쓰레드\t현재 초\n--------------------");
// create Thread instance with ThereadStart object
Thread t1 = new Thread(getThreadStart(1));
Thread t2 = new Thread(getThreadStart(2));
Thread t3 = new Thread(getThreadStart(3));
// create branch
t1.Start();
t2.Start();
t3.Start();
Thread.Sleep(10); // init thread
// main thread loop
while (true)
{
s++;
Console.WriteLine($"--------------------");
Thread.Sleep(1000);
}
}
}
}
문제 2번은 계좌와 사용자를 구현하는 문제입니다. 출력은 다음과 같습니다.
이 문제는 cs의 lock
statement를 사용할 줄 아는지 물어보는 문제라 할 수 있습니다. cs에서의 thread-safe를 위한 synchronous 구문은 lock
문을 사용하는데, 이를 위해서는 다음과 같이 lock object 를 정의해주어야 합니다.
[lock object, lock statement 에 대한 설명]
class Account
{
private readonly object lockObject = new object(); // lock object
public void func ()
{
lock (lockObject) // thread-safe statement
{
/* ... */
}
}
}
이러한 것을 구현한 코드는 다음과 같습니다.
using System;
namespace Problem_2
{
class Program
{
static void Main(string[] args)
{
// create Account and Teller instances
Account a = new Account(10000);
Teller user = new Teller("홍길동", a, 0);
// init variables
byte command = 0;
decimal insert;
// print user balance
user.printBalance();
// loop
while (command != 4)
{
Console.WriteLine("\n1. 입금\n2. 출금\n3. 조회\n4. 종료");
command = Convert.ToByte(Console.ReadLine());
switch (command)
{
case 1:
Console.Write("입금 금액: ");
insert = getInsert();
user.credit(insert);
break;
case 2:
Console.Write("출금 금액: ");
insert = getInsert();
user.debit(insert);
break;
case 3:
user.printBalance();
break;
case 4:
Console.WriteLine("이용해주셔서 감사합니다.");
break;
default:
Console.WriteLine("잘못 입력하셨습니다.");
break;
}
}
}
// return uesr input
static decimal getInsert ()
{
return Convert.ToDecimal(Console.ReadLine());
}
}
// Account class
class Account
{
// field
private decimal balance = 0;
private readonly object lockObject = new object(); // lock object
// constructor
public Account (decimal balance)
{
this.balance = balance;
}
// property
public decimal Balance
{
get { return balance; }
}
// methods
public void credit (decimal v) {
lock (lockObject) // synchronous thread
{
balance += v;
}
}
public bool debit (decimal v)
{
lock (lockObject) // synchronous thread
{
if (balance < v)
{
return false;
}
balance -= v;
return true;
}
}
}
// Teller class
class Teller
{
// field
private string name;
private Account account;
// constructor
public Teller (string name, Account account, decimal v)
{
this.name = name;
this.account = account;
account.credit(v);
}
// methods
public void printBalance ()
{
Console.WriteLine($"{name}님의 현재 잔액은 {account.Balance}원입니다.");
}
public void credit (decimal v)
{
account.credit(v);
Console.WriteLine($"{name}님의 입금 후 잔액은 {account.Balance} 입니다.");
}
public void debit (decimal v)
{
if (account.debit(v) == true)
{
Console.WriteLine($"{name}님의 출금 후 잔액은 {account.Balance} 입니다.");
} else
{
Console.WriteLine("잔액이 부족합니다.");
}
}
}
}