#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <inttypes.h>
#include <assert.h>
#include <unistd.h>

volatile int64_t bank_balance; // the current balance of the bank account
pthread_mutex_t bank_mutex; // used to protect the balance

void* ThreadMain(void *arg);
void die(char *);

int main(int argc, char *argv[]) {
	bank_balance = 0; // start with an empty account

	int ret = pthread_mutex_init(&bank_mutex, NULL);
	if (ret != 0) die("pthread_mutex_init()");

	// create the first banking customer
	pthread_t customer1;
	ret = pthread_create(&customer1, NULL, ThreadMain, NULL);
	if (ret != 0) die("pthread_create()");

	// create the second banking customer
	pthread_t customer2;
	ret = pthread_create(&customer2, NULL, ThreadMain, NULL);
	if (ret != 0) die("pthread_create()");

	// constantly print out the bank account balance
	for (;;) {
		ret = pthread_mutex_lock(&bank_mutex);
		if (ret != 0) die("pthread_mutex_lock()");

		int64_t cur_bal = bank_balance;

		assert(pthread_mutex_unlock(&bank_mutex) == 0);
		if (ret != 0) die("pthread_mutex_unlock()");

		printf("%" PRId64 "\n", cur_bal);
	}
}

void *ThreadMain(void *threadArgs) {
	pthread_detach(pthread_self());

	for (;;) {
		int ret = pthread_mutex_lock(&bank_mutex);
		if (ret != 0) die("pthread_mutex_lock()");

		bank_balance++;

		ret = pthread_mutex_unlock(&bank_mutex);
		if (ret != 0) die("pthread_mutex_unlock()");
	}
}

void die(char *str)
{
	fprintf(stderr, "%s", str);
	fflush(stderr);
	exit(1);
}
