운영체제 기말 시험으로
-. 프로그램에 반드시 포함해야 할 내용 요건
1. 시스템콜 사용
2. 멀티 쓰레드 활용
3. 동기화 활용
이해하기도 힘들었는데.. 활용이라니..
이런 시험이 나왔다.. 무려 시험 시간 9시간! 온라인 시험이라서 이런 시험도 가능했던 것 같다.
처음 1시간은 어떤 것을 만들까 생각했다. 그러다가 생각해낸 게 가계부였다. 그래서 9시간 동안 뚝딱뚝딱 만들었다.
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <pthread.h>
#include <stdlib.h>
#define BUF_SIZE 256
int money=0;
int flag[2] = { 0, 0 };
int turn = 0;
void income(void);
void outlay(void);
void enter_region(int process);
void leave_region(int process);
int main(void)
{
int number;
// 옵션 고르기
while (number != 4) {
printf("------------------------- 나만의 가계부 ------------------------------ \n\n\n");
printf("[1]지출 입력 [2]소득 입력 [3]차액 계산 [4]종료\n\n\n");
printf("옵션 선택 >>>> ");
scanf("%d", &number);
int fd, n, count;
char buf[BUF_SIZE];
//1번 지출 선택
if (number == 1) {
int first_pid = fork();
if (first_pid == 0) {
// 지출 내역에 대한 파일 만들기 , 읽기쓰기, 파일이 이미 존재한다면-1 리턴
fd = open("outlay.txt", O_RDWR | O_CREAT | O_EXCL, 0777);
// 이미 파일이 있을 경우에 파일 열기
if (fd == -1)
fd = open("outlay.txt", O_RDWR);
printf("입력 할 지출 내역 개수 : ");
scanf("%d", &count);
printf("\n\n\n");
// 지출 개수만큼만 입력할수 있음
write(1,"-----입력방식 >>> 전자제품 200000\n\n\n",sizeof("-----입력방식 >>> 전자제품 200000\n\n\n"));
while (count > 0) {
write(1, "지출 내역 : ", sizeof("지출 내역 : "));
//파일 읽어온후 , 입력한 내용 맨뒤에 삽입하고, 파일의 내용 출력
n = read(0, buf, BUF_SIZE);
lseek(fd, 0, SEEK_END);
n = write(fd, buf, n);
lseek(fd, 0, SEEK_SET);
n = read(fd, buf, BUF_SIZE);
n = write(1, buf, n);
write(1,"\n\n",sizeof("\n\n"));
count--;
}
close(fd);
return 0;
}
else {
wait(&first_pid);
printf("[1] 지출 내역 입력 종료\n\n\n");
}
}
//2번 수입 선택
else if (number == 2) {
int second_pid = fork();
if (second_pid == 0) {
// 소득 내역에 대한 파일 만들기, 읽기쓰기용, 파일 이미 존재한다면 -1 리턴
fd = open("income.txt", O_RDWR | O_CREAT | O_EXCL, 0777);
// 이미 파일 있는 경우 파일 열기
if (fd == -1)
fd = open("income.txt", O_RDWR);
printf("입력할 소득 내역 개수: ");
scanf("%d", &count);
printf("\n\n\n");
//소득 내역 입력한 개수만 입력
write(1,"-----입력방식 >>> 생활비 200000\n\n\n",sizeof("-----입력방식 >>> 생활비 200000\n\n\n"));
while (count > 0) {
write(1, "소득 내역 : ", sizeof("소득 내역 : "));
//파일 읽어온후 , 입력한 내용 맨뒤에 삽입하고, 파일의 내용 출력
n = read(0, buf, BUF_SIZE);
lseek(fd, 0, SEEK_END);
n = write(fd, buf, n);
lseek(fd, 0, SEEK_SET);
n = read(fd, buf, BUF_SIZE);
n = write(1, buf, n);
write(1,"\n\n",sizeof("\n\n"));
count--;
}
close(fd);
return 0;
}
else {
wait(&second_pid);
printf("[2] 소득 내역 입력 종료 \n\n\n");
}
}
else if (number == 3) {
pthread_t id;
pthread_t id2;
int thr_id;
int thr_id2;
void* tret;
thr_id = pthread_create(&id, NULL, outlay, NULL);
thr_id2 = pthread_create(&id2, NULL, income, NULL);
if (thr_id < 0)
{
perror("thread create error : ");
exit(0);
}
if (thr_id2 < 0)
{
perror("thread2 create error : ");
exit(0);
}
pthread_join(id, NULL);
pthread_join(id2, NULL);
printf("소득,지출의 차액 : %d\n\n\n",money);
}
// 두번 이상 확인 할 때를 위해 값 초기화
money = 0;
}
}
void income(void)
{
FILE* fp = fopen("income.txt", "r");
char buf[10000];
int i = 0;
char buf2[20];
if(fp == NULL)
{
perror("소득 내역이 없습니다");
exit(0);
}
enter_region(0);
while (!feof(fp)) {
//버퍼에 한라인 입력 받기
fgets(buf, sizeof(buf), fp);
char* ptr = strtok(buf, " ");
// 단어 하나하나 접근
while (ptr != NULL) {
// 문자열을 숫자만 money 변수에 저장하기
strcpy(buf2, ptr);
money += atoi(buf2);
ptr = strtok(NULL, " ");
}
}
// while 문이 한번더 실행 되어 반대로 한번 더해주기
money -= atoi(buf2);
leave_region(0);
fclose(fp);
}
void outlay(void)
{
FILE* fp = fopen("outlay.txt", "r");
char buf[10000];
int i = 0;
char buf2[20];
if(fp == NULL)
{
perror("지출 내역이 없습니다");
exit(0);
}
enter_region(1);
while (!feof(fp)) {
//버퍼에 한라인 입력 받기
fgets(buf, sizeof(buf), fp);
char* ptr = strtok(buf, " ");
// 단어 하나하나 접근
while (ptr != NULL) {
// 문자열을 숫자만 money 변수에 저장하기
strcpy(buf2, ptr);
money += -(atoi(buf2));
ptr = strtok(NULL, " ");
}
}
// while 문이 한번더 실행 되어 반대로 한번 더해주기
money += atoi(buf2);
leave_region(1);
fclose(fp);
}
void enter_region(int process)
{
int other = 1 - process;
flag[process] = 1;
turn = 1 - process;
while((turn == 1 - process) && (flag[other] == 1)) {}
}
void leave_region(int process)
{
flag[process] = 0;
}
깔끔.. 하지는 않다. 정해진 시간 안에 완료해야 했고, 세 가지를 모두 활용해 코드를 짰기 때문에 ,
불필요하다고 느끼는 부분도 있을 것 같다!
1. 시스템 콜 활용 부분
int first_pid = fork();
wait(&first_pid);
n = read(0, buf, BUF_SIZE);
write 함수도 있지만 생략하겠다. 시스템 콜을 활용한 부분은 사용자가
메뉴 중 한 가지를 선택했을 때, 다른 작업을 위해, 자식 프로세스를 생성하고 그 작업이 끝날 때까지
기다려주는 방식을 사용하여 시스템 콜을 활용했다.
2. 멀티스레드 활용
thr_id = pthread_create(&id, NULL, outlay, NULL);
thr_id2 = pthread_create(&id2, NULL, income, NULL);
if (thr_id < 0)
{
perror("thread create error : ");
exit(0);
}
if (thr_id2 < 0)
{
perror("thread2 create error : ");
exit(0);
}
pthread_join(id, NULL);
pthread_join(id2, NULL);
printf("소득,지출의 차액 : %d\n\n\n",money);
메뉴 중에, [3] 차액 계산 부분에서 멀티 스레드를 활용하였다.
소득 부분을 계산하는 함수 , 지출 부분을 계산하는 함수를 멀티 쓰레드를 생성해서 함수를 실행시켰다.
3. 동기화 활용
void enter_region(int process)
{
int other = 1 - process;
flag[process] = 1;
turn = 1 - process;
while((turn == 1 - process) && (flag[other] == 1)) {}
}
void leave_region(int process)
{
flag[process] = 0;
}
피터슨 알고리즘을 활용하였다. flag와 turn이라는 변수로 임계 영역에 들어갈 프로세스를 결정하였다.
flag는 누가 임계 영역에 진입할 것인지 나타내고, turn 은 누가 임계영역에 들어갈 차례인지 나타내는 변수이다.
int flag[2] = { 0, 0 };
int turn = 0;
1. flag [0] = 1(즉, true)로 설정하여 0번 스레드가 임계 영역 진입을 하고 싶다고 표시한다.
2. 이때 turn = 1을 주며 1번 프로세스가 먼저 들어가라고 양보해준다.
3. 만약 이때 콘텍스트 스위칭이 되지 않았다면 while문에 갇히게 된다.
4. 1번 프로세스가 이제 모든 작업을 끝내면 turn = 0, flag [1] = 0(즉, false)가 되므로 0번 프로세스가 다시 돌 수 있다.