#include <stdio.h>
#include <pthread.h>
int counter = 0;
void *increase();
void *decrease();
int balance = 500;
void *deposit(void*);
void *withdraw(void*);
int main() {
pthread_t t_inc, t_dec;
int dep_money = 300;
int wd_money = 100;
pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_create(&t_dec, NULL, withdraw, &wd_money);
// Wait until the thread is finished
pthread_join(t_inc, NULL);
pthread_join(t_dec, NULL);
}
return 0;
}
// Functions for thread
void *deposit(void *args) {
int *money = (int *)args;
balance += *money;
printf("Deposit: New balance: %d\n", balance);
return NULL;
}
void *withdraw(void *args) {
int *money = (int *)args;
if (balance < *money) {
printf("Not enough balance\n");
} else {
balance -= *money;
printf("Withdraw: New balance: %d\n", balance);
}
return NULL;
}
For macOS:
Deposit: New balance: 800
Withdraw: New balance: 700
For Ubuntu:
Withdraw: New balance: 400
Deposit: New balance: 700
pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_join(t_inc, NULL);
pthread_create(&t_dec, NULL, withdraw, &w_money);
pthread_join(t_dec, NULL);
In conclusion, my question is why in the first code run in Ubuntu it didn't run as the first order of the pthread_join(t_inc, NULL); then the second pthread_join(t_dec, NULL); instead it runs the opposite? And I had to call pthread_join() after pthread_create() immediately for it to work in order which I don't think it's efficient since I didn't create the second thread yet.
That's just a race condition. Calling pthread_create
of one thread before that of the other does not guarantee that the second thread shall be scheduled by the OS after the first. So calling
pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_create(&t_dec, NULL, withdraw, &wd_money);
doesn't mean that you'll invoke the thread running deposit()
before the one running withdraw()
. It's totally up to the OS on when they are actually scheduled and as a programmer, one should not make any assumptions about it. Hence the discrepancies in the result because any one of the thread might run before.
So, to answer your question
my question is why in the first code run in Ubuntu it didn't run as the first order of the pthread_join(t_inc, NULL); then the second pthread_join(t_dec, NULL); instead it runs the opposite?
Don't have any expectations about the order in which threads are actually run.
Calling
pthread_create(&t_inc, NULL, deposit, &dep_money);
pthread_join(t_inc, NULL);
pthread_create(&t_dec, NULL, withdraw, &w_money);
pthread_join(t_dec, NULL);
will always work since you have essentially serialized the thread creation and the thread calling deposit()
shall always complete before the one running withdraw()
is spawned and thus it works on all OSs.
EDIT:
For completeness, as you mentioned, creating threads and immediately calling join()
isn't really of much use since it is as good as just calling the functions deposit()
and withdraw()
in order, given that here deposit()
and withdraw()
don't really do much significant work that might stall the main thread, blocking it to proceed to do other tasks. Also, you would usually need to take care of shared variables. e.g. If you just had a single variable amount
and then each thread updated the same value, one adding balance and another deducting it, then you could be possibly needing constructs like mutex
/condition_variable
to achieve your desired results, free of race conditions.