1// bank_account.c
2// 뮤텍스를 이용한 스레드 안전 은행 계좌
3#include <stdio.h>
4#include <stdlib.h>
5#include <pthread.h>
6#include <unistd.h>
7#include <time.h>
8
9typedef struct {
10 int balance;
11 pthread_mutex_t lock;
12} Account;
13
14Account* account_create(int initial_balance) {
15 Account* acc = malloc(sizeof(Account));
16 acc->balance = initial_balance;
17 pthread_mutex_init(&acc->lock, NULL);
18 return acc;
19}
20
21void account_destroy(Account* acc) {
22 pthread_mutex_destroy(&acc->lock);
23 free(acc);
24}
25
26int account_deposit(Account* acc, int amount) {
27 pthread_mutex_lock(&acc->lock);
28
29 acc->balance += amount;
30 int new_balance = acc->balance;
31
32 pthread_mutex_unlock(&acc->lock);
33 return new_balance;
34}
35
36int account_withdraw(Account* acc, int amount) {
37 pthread_mutex_lock(&acc->lock);
38
39 if (acc->balance >= amount) {
40 acc->balance -= amount;
41 int new_balance = acc->balance;
42 pthread_mutex_unlock(&acc->lock);
43 return new_balance;
44 }
45
46 pthread_mutex_unlock(&acc->lock);
47 return -1; // 잔액 부족
48}
49
50int account_get_balance(Account* acc) {
51 pthread_mutex_lock(&acc->lock);
52 int balance = acc->balance;
53 pthread_mutex_unlock(&acc->lock);
54 return balance;
55}
56
57// 이체 (두 계좌 간)
58int account_transfer(Account* from, Account* to, int amount) {
59 // 데드락 방지: 항상 같은 순서로 잠금
60 // 주소값이 작은 계좌 먼저 잠금
61 Account* first = (from < to) ? from : to;
62 Account* second = (from < to) ? to : from;
63
64 pthread_mutex_lock(&first->lock);
65 pthread_mutex_lock(&second->lock);
66
67 int result = -1;
68 if (from->balance >= amount) {
69 from->balance -= amount;
70 to->balance += amount;
71 result = from->balance;
72 }
73
74 pthread_mutex_unlock(&second->lock);
75 pthread_mutex_unlock(&first->lock);
76
77 return result;
78}
79
80// 테스트용 스레드 데이터
81typedef struct {
82 Account* acc;
83 int thread_id;
84} ThreadArg;
85
86void* depositor(void* arg) {
87 ThreadArg* ta = (ThreadArg*)arg;
88
89 for (int i = 0; i < 100; i++) {
90 int new_balance = account_deposit(ta->acc, 100);
91 printf("[입금자 %d] 입금 100원 -> 잔액: %d\n", ta->thread_id, new_balance);
92 usleep(rand() % 10000);
93 }
94
95 return NULL;
96}
97
98void* withdrawer(void* arg) {
99 ThreadArg* ta = (ThreadArg*)arg;
100
101 for (int i = 0; i < 100; i++) {
102 int result = account_withdraw(ta->acc, 100);
103 if (result >= 0) {
104 printf("[출금자 %d] 출금 100원 -> 잔액: %d\n", ta->thread_id, result);
105 } else {
106 printf("[출금자 %d] 잔액 부족\n", ta->thread_id);
107 }
108 usleep(rand() % 10000);
109 }
110
111 return NULL;
112}
113
114int main(void) {
115 srand(time(NULL));
116
117 Account* acc = account_create(10000);
118 printf("초기 잔액: %d\n\n", account_get_balance(acc));
119
120 pthread_t depositors[3];
121 pthread_t withdrawers[3];
122 ThreadArg args[6];
123
124 // 입금자 3명
125 for (int i = 0; i < 3; i++) {
126 args[i].acc = acc;
127 args[i].thread_id = i;
128 pthread_create(&depositors[i], NULL, depositor, &args[i]);
129 }
130
131 // 출금자 3명
132 for (int i = 0; i < 3; i++) {
133 args[i + 3].acc = acc;
134 args[i + 3].thread_id = i;
135 pthread_create(&withdrawers[i], NULL, withdrawer, &args[i + 3]);
136 }
137
138 // 대기
139 for (int i = 0; i < 3; i++) {
140 pthread_join(depositors[i], NULL);
141 pthread_join(withdrawers[i], NULL);
142 }
143
144 printf("\n최종 잔액: %d\n", account_get_balance(acc));
145 printf("예상 잔액: %d (초기 10000 + 입금 30000 - 출금 최대 30000)\n", 10000);
146
147 account_destroy(acc);
148 return 0;
149}