P10 lab code added
This commit is contained in:
parent
c7d4ec972e
commit
382018f539
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: coffeTeller.c
|
||||||
|
* Purpose: simple sequence with semaphores
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
sem_t *coin, *coffee, *ready;
|
||||||
|
|
||||||
|
// set up a semaphore
|
||||||
|
coin = sem_open(COIN_SEMAPHOR, 0);
|
||||||
|
coffee = sem_open(COFFEE_SEMAPHOR, 0);
|
||||||
|
ready = sem_open(READY_SEMAPHOR, 0);
|
||||||
|
|
||||||
|
// start teller machine
|
||||||
|
printf("\nCoffee teller machine starting\n\n");
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < ITERS) {
|
||||||
|
printf("teller (%d): waiting for coin\n", i);
|
||||||
|
printf(" (%d): got coin\n", i);
|
||||||
|
printf(" (%d): dispense coffee\n", i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef MY_DEFINITIONS_HEADER
|
||||||
|
#define MY_DEFINITIONS_HEADER
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: commonDefs.h
|
||||||
|
* Purpose: common definitions
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013, 4/2014
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#define MYTURN_SEMAPHOR "/my_semaphor_1_name_advaneced_seq"
|
||||||
|
#define COIN_SEMAPHOR "/my_semaphor_2_name_advaneced_seq"
|
||||||
|
#define COFFEE_SEMAPHOR "/my_semaphor_3_name_advaneced_seq"
|
||||||
|
#define READY_SEMAPHOR "/my_semaphor_4_name_advaneced_seq"
|
||||||
|
|
||||||
|
#define ITERS (100*1000*1000)
|
||||||
|
#define CUSTOMERS 4
|
||||||
|
#define NUM_COIN 3
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#define checkSem(X) {if (X == SEM_FAILED) {perror("sem_open"); exit(-1);}}
|
||||||
|
|
||||||
|
#define drinkingCoffee(X) {usleep((((1+X)*rand())+100000)&0xFFFFF);}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: customer.c
|
||||||
|
* Purpose: simple sequence with semaphores
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
int i, myID;
|
||||||
|
sem_t *myTurn, *coin, *coffee, *ready;
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
myID = atoi(argv[1]);
|
||||||
|
else
|
||||||
|
myID = 0;
|
||||||
|
|
||||||
|
// set up a semaphore
|
||||||
|
myTurn = sem_open(MYTURN_SEMAPHOR, 0);
|
||||||
|
coin = sem_open(COIN_SEMAPHOR, 0);
|
||||||
|
coffee = sem_open(COFFEE_SEMAPHOR, 0);
|
||||||
|
ready = sem_open(READY_SEMAPHOR, 0);
|
||||||
|
|
||||||
|
// start customer
|
||||||
|
printf("Customer starting (%d)\n", myID);
|
||||||
|
|
||||||
|
// now check the sum
|
||||||
|
for (i = 0; i < ITERS; i++) {
|
||||||
|
printf("\t\t\t\tcustomer(%d) put coin %d\n", myID, i);
|
||||||
|
printf("\t\t\t\tcustomer(%d) waiting for coffee %d\n", myID, i);
|
||||||
|
printf("\t\t\t\tcustomer(%d) got coffee %d\n", myID, i);
|
||||||
|
drinkingCoffee(myID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,40 @@
|
||||||
|
# BSy M. Thaler
|
||||||
|
# Version v.fs20
|
||||||
|
|
||||||
|
CMP= gcc -std=gnu99
|
||||||
|
CMPFLAGS= -Wall -g
|
||||||
|
LIB= -pthread
|
||||||
|
EXENAME0= startApp.e
|
||||||
|
EXENAME1= coffeeTeller.e
|
||||||
|
EXENAME2= customer.e
|
||||||
|
|
||||||
|
doit:
|
||||||
|
@make --no-print-directory clean
|
||||||
|
@make --no-print-directory startApp
|
||||||
|
@make --no-print-directory coffeeTeller
|
||||||
|
@make --no-print-directory customer
|
||||||
|
|
||||||
|
startApp: startApp.o
|
||||||
|
$(CMP) $(CMPFLAGS) startApp.o $(LIB) -o $(EXENAME0)
|
||||||
|
|
||||||
|
coffeeTeller: coffeeTeller.o
|
||||||
|
$(CMP) $(CMPFLAGS) coffeeTeller.o $(LIB) -o $(EXENAME1)
|
||||||
|
|
||||||
|
customer: customer.o
|
||||||
|
$(CMP) $(CMPFLAGS) customer.o $(LIB) -o $(EXENAME2)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CMP) -c $(CMPFLAGS) $<
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
$(CMP) -c $(CMPFLAGS) $<
|
||||||
|
|
||||||
|
all:
|
||||||
|
@make clean
|
||||||
|
make doit
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f *.e *.o
|
||||||
|
|
||||||
|
purge:
|
||||||
|
@make clean
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: startApp.c
|
||||||
|
* Purpose: ice cream teller, basic sequence
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
int j;
|
||||||
|
char string[8];
|
||||||
|
sem_t *access, *coin, *coffee, *ready;
|
||||||
|
pid_t tellerPID;
|
||||||
|
|
||||||
|
sem_unlink(MYTURN_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
sem_unlink(COIN_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
sem_unlink(COFFEE_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
sem_unlink(READY_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
|
||||||
|
// set up a semaphore (? -> initial value of semaphor)
|
||||||
|
// checkSem() -> macro defined in commonDefs.h
|
||||||
|
|
||||||
|
/*
|
||||||
|
access = sem_open(MYTURN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(access);
|
||||||
|
coin = sem_open(COIN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coin);
|
||||||
|
coffee = sem_open(COFFEE_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coffee);
|
||||||
|
ready = sem_open(READY_SEMAPHOR, O_CREAT, 0700, ?); checkSem(ready);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// now that the resources are set up, the supervisor can be started
|
||||||
|
for (j = 1; j <= CUSTOMERS; j++) {
|
||||||
|
if (fork() == 0) {
|
||||||
|
sprintf(string, "%d", j);
|
||||||
|
execl("./customer.e", "customer.e", string, NULL);
|
||||||
|
printf("*** could not start customer.e ***\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tellerPID = fork()) == 0) {
|
||||||
|
execl("./coffeeTeller.e", "coffeeTeller.e", "0", NULL);
|
||||||
|
printf("*** could not start coffeTeller ***\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
waitpid(tellerPID, NULL, 0);
|
||||||
|
system("killall coffeeTeller.e");
|
||||||
|
system("killall customer.e"); // kill all customers
|
||||||
|
|
||||||
|
// clean up resources
|
||||||
|
sem_unlink(MYTURN_SEMAPHOR);
|
||||||
|
sem_unlink(COIN_SEMAPHOR);
|
||||||
|
sem_unlink(COFFEE_SEMAPHOR);
|
||||||
|
sem_unlink(READY_SEMAPHOR);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,103 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: banking.c
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "banking.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
typedef struct account_struct_ {
|
||||||
|
long int balance;
|
||||||
|
pthread_mutex_t acntLock;
|
||||||
|
} Account;
|
||||||
|
|
||||||
|
typedef struct branch_struct {
|
||||||
|
Account *accounts;
|
||||||
|
pthread_mutex_t branchLock;
|
||||||
|
} Branch;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
static Branch *Bank;
|
||||||
|
static int nBranches, nAccounts;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// banking functions
|
||||||
|
|
||||||
|
void makeBank(int num_branches, int num_accounts) {
|
||||||
|
nBranches = num_branches;
|
||||||
|
nAccounts = num_accounts;
|
||||||
|
Bank = (Branch *)malloc(nBranches * sizeof(Branch));
|
||||||
|
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
pthread_mutexattr_init(&attr);
|
||||||
|
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
Bank[i].accounts = (Account *)malloc(nAccounts * sizeof(Account));
|
||||||
|
pthread_mutex_init(&(Bank[i].branchLock), &attr);
|
||||||
|
for (int j = 0; j < nAccounts; j++) {
|
||||||
|
Bank[i].accounts[j].balance = 0;
|
||||||
|
pthread_mutex_init((&(Bank[i].accounts[j].acntLock)), &attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteBank(void) {
|
||||||
|
for (int i = 0; i < nBranches; i++)
|
||||||
|
free(Bank[i].accounts);
|
||||||
|
free(Bank);
|
||||||
|
nBranches = nAccounts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long int withdraw(int branchNr, int accountNr, long int value) {
|
||||||
|
int rv, tmp;
|
||||||
|
rv = 0;
|
||||||
|
tmp = Bank[branchNr].accounts[accountNr].balance - value;
|
||||||
|
if (tmp >= 0) {
|
||||||
|
Bank[branchNr].accounts[accountNr].balance = tmp;
|
||||||
|
rv = value;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deposit(int branchNr, int accountNr, long int value) {
|
||||||
|
Bank[branchNr].accounts[accountNr].balance += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer(int fromB, int toB, int accountNr, long int value) {
|
||||||
|
int money = withdraw(fromB, accountNr, value);
|
||||||
|
if (money >= 0)
|
||||||
|
deposit(toB, accountNr, money);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkAssets(void) {
|
||||||
|
static long assets = 0;
|
||||||
|
long sum = 0;
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
for (int j = 0; j < nAccounts; j++) {
|
||||||
|
sum += (long)Bank[i].accounts[j].balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (assets == 0) {
|
||||||
|
assets = sum;
|
||||||
|
printf("Balance of accounts is: %ld\n", sum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (sum != assets)
|
||||||
|
printf("Balance of accounts is: %ld ... not correct\n", sum);
|
||||||
|
else
|
||||||
|
printf("Balance of accounts is: %ld ... correct\n", assets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: banking.h
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
// banking functions
|
||||||
|
|
||||||
|
void makeBank(int num_branches, int num_accounts);
|
||||||
|
void deleteBank(void);
|
||||||
|
|
||||||
|
long int withdraw(int branchNr, int accountNr, long int value) ;
|
||||||
|
void deposit(int branchNr, int accountNr, long int value);
|
||||||
|
void transfer(int fromB, int toB, int accountNr, long int value);
|
||||||
|
void checkAssets(void);
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: main.c
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "banking.h"
|
||||||
|
#include "mtimer.h"
|
||||||
|
#include "mrandom.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// constant values
|
||||||
|
|
||||||
|
#define MAX_THREADS 16
|
||||||
|
#define NUM_THREADS 4
|
||||||
|
|
||||||
|
#define TRANSFERS (16*1024*1024)
|
||||||
|
#define ACCOUNTS (2048)
|
||||||
|
#define BRANCHES (128)
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// globals
|
||||||
|
|
||||||
|
int nThreads;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// pusher
|
||||||
|
|
||||||
|
void *pusher(void *arg) {
|
||||||
|
int idx = (int)(long)(arg);
|
||||||
|
mrand_t rand;
|
||||||
|
unsigned int seed = 17*idx;
|
||||||
|
mrandInit(seed, &rand);
|
||||||
|
int account, from, to, val;
|
||||||
|
int count = TRANSFERS / nThreads;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
account = (int)(mrandUInt(&rand) % ACCOUNTS);
|
||||||
|
from = (int)(mrandUInt(&rand) % BRANCHES);
|
||||||
|
to = (int)(mrandUInt(&rand) % BRANCHES);
|
||||||
|
val = (int)(mrandRange(1000, 100000, &rand));
|
||||||
|
val = withdraw(from, account, val);
|
||||||
|
if (val > 0)
|
||||||
|
deposit(to, account, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// main program
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
gtimer_t timer;
|
||||||
|
mrand_t ranvar;
|
||||||
|
long assets;
|
||||||
|
|
||||||
|
// thread id's
|
||||||
|
pthread_t th[MAX_THREADS];
|
||||||
|
|
||||||
|
// get number of threads or default
|
||||||
|
if (argc > 1)
|
||||||
|
nThreads = atoi(argv[1]);
|
||||||
|
else
|
||||||
|
nThreads = NUM_THREADS;
|
||||||
|
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
|
||||||
|
|
||||||
|
mrandInit((MAX_THREADS + 1)*333, &ranvar);
|
||||||
|
|
||||||
|
printf("\nRunning %d threads\n", nThreads);
|
||||||
|
makeBank(BRANCHES, ACCOUNTS);
|
||||||
|
for (int i = 0; i < ACCOUNTS; i++)
|
||||||
|
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
|
||||||
|
checkAssets();
|
||||||
|
|
||||||
|
startGTimer(timer);
|
||||||
|
// create threads and pass thread number
|
||||||
|
for (long i = 0; i < nThreads; i++)
|
||||||
|
pthread_create(&th[i], NULL, pusher, (void *)i);
|
||||||
|
// wait for threads to terminate
|
||||||
|
for (int i = 0; i < nThreads; i++)
|
||||||
|
pthread_join(th[i], NULL);
|
||||||
|
stopGTimer(timer);
|
||||||
|
|
||||||
|
checkAssets();
|
||||||
|
printGTime(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,32 @@
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Makefile
|
||||||
|
# Course: BSy
|
||||||
|
# Date: M. Thaler, 1/2016
|
||||||
|
# File: makefile
|
||||||
|
# Version: v.fs20
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
#macros
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLGS = -std=gnu99
|
||||||
|
LIBS = -pthread
|
||||||
|
OFILES = main.o banking.o
|
||||||
|
HFILES = banking.h
|
||||||
|
|
||||||
|
main: $(OFILES) $(HFILES)
|
||||||
|
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLGS) -c $<
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
$(CC) $(CFLGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.e
|
||||||
|
@echo "directory cleaned"
|
||||||
|
|
||||||
|
all:
|
||||||
|
@rm -f *.o
|
||||||
|
make --no-print-directory main
|
||||||
|
#-----------------------------------------------------------------------------
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
|
||||||
|
#define MY_RANDOMGENERATOR_DEFINITIONS
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: mrandom.h
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: thread safe random functions (reentrant)
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
// date type: mrand_t
|
||||||
|
//
|
||||||
|
// functions:
|
||||||
|
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
|
||||||
|
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
|
||||||
|
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
|
||||||
|
// -> random number within range
|
||||||
|
//
|
||||||
|
/******************************************************************************/
|
||||||
|
// constanst for ecuyer generator: length approx 8 x 10^12
|
||||||
|
|
||||||
|
#define M1 2147483563
|
||||||
|
#define M2 2147483399
|
||||||
|
#define A1 40014
|
||||||
|
#define A2 40692
|
||||||
|
#define Q1 53668
|
||||||
|
#define Q2 52774
|
||||||
|
#define R1 12211
|
||||||
|
#define R2 3791
|
||||||
|
#define MRAND_MAX M1-1
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
typedef struct mrand_t { unsigned int s1; \
|
||||||
|
unsigned int s2; } mrand_t;
|
||||||
|
|
||||||
|
void mrandInit(unsigned int seed, mrand_t *mrt) {
|
||||||
|
mrt->s1 = 33777 + seed * 777;
|
||||||
|
mrt->s2 = 9777572 + seed * 33775;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mrandUInt(mrand_t *mrt) {
|
||||||
|
unsigned int rv;
|
||||||
|
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
|
||||||
|
if (mrt->s1 <= 0) mrt->s1 += M1;
|
||||||
|
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
|
||||||
|
if (mrt->s2 <= 0) mrt->s2 += M2;
|
||||||
|
rv = (mrt->s1 + mrt->s2) % M1;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mrandDouble(mrand_t *mrt) {
|
||||||
|
unsigned int rv;
|
||||||
|
double dv;
|
||||||
|
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
|
||||||
|
if (mrt->s1 <= 0) mrt->s1 += M1;
|
||||||
|
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
|
||||||
|
if (mrt->s2 <= 0) mrt->s2 += M2;
|
||||||
|
rv = (mrt->s1 + mrt->s2) % M1;
|
||||||
|
dv = (double)rv / ((double)(M1-1));
|
||||||
|
return dv;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
|
||||||
|
assert(low <= high);
|
||||||
|
double drv = mrandDouble(mrt);
|
||||||
|
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
|
||||||
|
return low + av;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
#endif
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef TIMER_MACRO_DEFINITIONS
|
||||||
|
#define TIMER_MACRO_DEFINITIONS
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
// Course: BSy
|
||||||
|
// File: mtimer.h
|
||||||
|
// Purpose: timer functions gettimeofday()
|
||||||
|
// Author: M. Thaler, ZHAW, 1/2016
|
||||||
|
// Version: v.fs20
|
||||||
|
/******************************************************************************/
|
||||||
|
// gettimeofday()
|
||||||
|
// function: elapsed time: between start and stop
|
||||||
|
// data type: gtimer_t
|
||||||
|
// functions: startGTimer(gtimer_t tdata) -> start timer
|
||||||
|
// stopGTimer(gtimer_t tdata) -> stop timer
|
||||||
|
// double getWallGTime(gtimer_t tdata) -> get time in s
|
||||||
|
// printGTime(X) -> print time in s
|
||||||
|
//
|
||||||
|
// -> see also "man gettimeofday"
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/times.h>
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
typedef struct gtimer_t { struct timeval sT; \
|
||||||
|
struct timeval eT; } gtimer_t;
|
||||||
|
|
||||||
|
#define startGTimer(X) gettimeofday(&X.sT, NULL)
|
||||||
|
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
|
||||||
|
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
|
||||||
|
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
|
||||||
|
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
./main.e 1
|
||||||
|
./main.e 2
|
||||||
|
./main.e 4
|
|
@ -0,0 +1,19 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: banking.h
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
// banking functions
|
||||||
|
|
||||||
|
void makeBank(int num_branches, int num_accounts);
|
||||||
|
void deleteBank(void);
|
||||||
|
|
||||||
|
long int withdraw(int branchNr, int accountNr, long int value) ;
|
||||||
|
void deposit(int branchNr, int accountNr, long int value);
|
||||||
|
void transfer(int fromB, int toB, int accountNr, long int value);
|
||||||
|
void checkAssets(void);
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: main.c
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "banking.h"
|
||||||
|
#include "mtimer.h"
|
||||||
|
#include "mrandom.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// constant values
|
||||||
|
|
||||||
|
#define MAX_THREADS 16
|
||||||
|
#define NUM_THREADS 4
|
||||||
|
|
||||||
|
#define TRANSFERS (16*1024*1024)
|
||||||
|
#define ACCOUNTS (2048)
|
||||||
|
#define BRANCHES (128)
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// globals
|
||||||
|
|
||||||
|
int nThreads;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// pusher
|
||||||
|
|
||||||
|
void *pusher(void *arg) {
|
||||||
|
int idx = (int)(long)(arg);
|
||||||
|
mrand_t rand;
|
||||||
|
unsigned int seed = 17*idx;
|
||||||
|
mrandInit(seed, &rand);
|
||||||
|
int account, from, to, val;
|
||||||
|
int count = TRANSFERS / nThreads;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
account = (int)(mrandUInt(&rand) % ACCOUNTS);
|
||||||
|
from = (int)(mrandUInt(&rand) % BRANCHES);
|
||||||
|
to = (int)(mrandUInt(&rand) % BRANCHES);
|
||||||
|
val = (int)(mrandRange(1000, 100000, &rand));
|
||||||
|
val = withdraw(from, account, val);
|
||||||
|
deposit(to, account, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// main program
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
gtimer_t timer;
|
||||||
|
mrand_t ranvar;
|
||||||
|
long assets;
|
||||||
|
|
||||||
|
// thread id's
|
||||||
|
pthread_t th[MAX_THREADS];
|
||||||
|
|
||||||
|
// get number of threads or default
|
||||||
|
if (argc > 1)
|
||||||
|
nThreads = atoi(argv[1]);
|
||||||
|
else
|
||||||
|
nThreads = NUM_THREADS;
|
||||||
|
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
|
||||||
|
|
||||||
|
mrandInit((MAX_THREADS + 1)*333, &ranvar);
|
||||||
|
|
||||||
|
printf("\nRunning %d threads\n", nThreads);
|
||||||
|
makeBank(BRANCHES, ACCOUNTS);
|
||||||
|
for (int i = 0; i < ACCOUNTS; i++)
|
||||||
|
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
|
||||||
|
checkAssets();
|
||||||
|
|
||||||
|
startGTimer(timer);
|
||||||
|
// create threads and pass thread number
|
||||||
|
for (long i = 0; i < nThreads; i++)
|
||||||
|
pthread_create(&th[i], NULL, pusher, (void *)i);
|
||||||
|
// wait for threads to terminate
|
||||||
|
for (int i = 0; i < nThreads; i++)
|
||||||
|
pthread_join(th[i], NULL);
|
||||||
|
stopGTimer(timer);
|
||||||
|
|
||||||
|
checkAssets();
|
||||||
|
printGTime(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,32 @@
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Makefile
|
||||||
|
# Course: BSy
|
||||||
|
# Date: M. Thaler, 1/2016
|
||||||
|
# File: makefile
|
||||||
|
# Version: v.fs20
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
#macros
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLGS = -std=gnu99
|
||||||
|
LIBS = -pthread
|
||||||
|
OFILES = main.o banking.o
|
||||||
|
HFILES = banking.h
|
||||||
|
|
||||||
|
main: $(OFILES) $(HFILES)
|
||||||
|
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLGS) -c $<
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
$(CC) $(CFLGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.e
|
||||||
|
@echo "directory cleaned"
|
||||||
|
|
||||||
|
all:
|
||||||
|
@rm -f *.o
|
||||||
|
make --no-print-directory main
|
||||||
|
#-----------------------------------------------------------------------------
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
|
||||||
|
#define MY_RANDOMGENERATOR_DEFINITIONS
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: mrandom.h
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: thread safe random functions (reentrant)
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
// date type: mrand_t
|
||||||
|
//
|
||||||
|
// functions:
|
||||||
|
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
|
||||||
|
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
|
||||||
|
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
|
||||||
|
// -> random number within range
|
||||||
|
//
|
||||||
|
/******************************************************************************/
|
||||||
|
// constanst for ecuyer generator: length approx 8 x 10^12
|
||||||
|
|
||||||
|
#define M1 2147483563
|
||||||
|
#define M2 2147483399
|
||||||
|
#define A1 40014
|
||||||
|
#define A2 40692
|
||||||
|
#define Q1 53668
|
||||||
|
#define Q2 52774
|
||||||
|
#define R1 12211
|
||||||
|
#define R2 3791
|
||||||
|
#define MRAND_MAX M1-1
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
typedef struct mrand_t { unsigned int s1; \
|
||||||
|
unsigned int s2; } mrand_t;
|
||||||
|
|
||||||
|
void mrandInit(unsigned int seed, mrand_t *mrt) {
|
||||||
|
mrt->s1 = 33777 + seed * 777;
|
||||||
|
mrt->s2 = 9777572 + seed * 33775;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mrandUInt(mrand_t *mrt) {
|
||||||
|
unsigned int rv;
|
||||||
|
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
|
||||||
|
if (mrt->s1 <= 0) mrt->s1 += M1;
|
||||||
|
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
|
||||||
|
if (mrt->s2 <= 0) mrt->s2 += M2;
|
||||||
|
rv = (mrt->s1 + mrt->s2) % M1;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mrandDouble(mrand_t *mrt) {
|
||||||
|
unsigned int rv;
|
||||||
|
double dv;
|
||||||
|
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
|
||||||
|
if (mrt->s1 <= 0) mrt->s1 += M1;
|
||||||
|
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
|
||||||
|
if (mrt->s2 <= 0) mrt->s2 += M2;
|
||||||
|
rv = (mrt->s1 + mrt->s2) % M1;
|
||||||
|
dv = (double)rv / ((double)(M1-1));
|
||||||
|
return dv;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
|
||||||
|
assert(low <= high);
|
||||||
|
double drv = mrandDouble(mrt);
|
||||||
|
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
|
||||||
|
return low + av;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
#endif
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef TIMER_MACRO_DEFINITIONS
|
||||||
|
#define TIMER_MACRO_DEFINITIONS
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
// Course: BSy
|
||||||
|
// File: mtimer.h
|
||||||
|
// Purpose: timer functions gettimeofday()
|
||||||
|
// Author: M. Thaler, ZHAW, 1/2016
|
||||||
|
// Version: v.fs20
|
||||||
|
/******************************************************************************/
|
||||||
|
// gettimeofday()
|
||||||
|
// function: elapsed time: between start and stop
|
||||||
|
// data type: gtimer_t
|
||||||
|
// functions: startGTimer(gtimer_t tdata) -> start timer
|
||||||
|
// stopGTimer(gtimer_t tdata) -> stop timer
|
||||||
|
// double getWallGTime(gtimer_t tdata) -> get time in s
|
||||||
|
// printGTime(X) -> print time in s
|
||||||
|
//
|
||||||
|
// -> see also "man gettimeofday"
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/times.h>
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
typedef struct gtimer_t { struct timeval sT; \
|
||||||
|
struct timeval eT; } gtimer_t;
|
||||||
|
|
||||||
|
#define startGTimer(X) gettimeofday(&X.sT, NULL)
|
||||||
|
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
|
||||||
|
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
|
||||||
|
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
|
||||||
|
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
./main.e 1
|
||||||
|
./main.e 2
|
||||||
|
./main.e 4
|
|
@ -0,0 +1,119 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: banking.c
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "banking.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
typedef struct account_struct_ {
|
||||||
|
long int balance;
|
||||||
|
pthread_mutex_t acntLock;
|
||||||
|
} Account;
|
||||||
|
|
||||||
|
typedef struct branch_struct {
|
||||||
|
Account *accounts;
|
||||||
|
pthread_mutex_t branchLock;
|
||||||
|
} Branch;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
static Branch *bank;
|
||||||
|
static int nBranches, nAccounts;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// banking functions
|
||||||
|
|
||||||
|
void makeBank(int num_branches, int num_accounts) {
|
||||||
|
nBranches = num_branches;
|
||||||
|
nAccounts = num_accounts;
|
||||||
|
bank = (Branch *)malloc(nBranches * sizeof(Branch));
|
||||||
|
|
||||||
|
pthread_mutexattr_t attr;
|
||||||
|
pthread_mutexattr_init(&attr);
|
||||||
|
//pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
|
||||||
|
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
bank[i].accounts = (Account *)malloc(nAccounts * sizeof(Account));
|
||||||
|
for (int j = 0; j < nAccounts; j++) {
|
||||||
|
bank[i].accounts[j].balance = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void deletebank(void) {
|
||||||
|
for (int i = 0; i < nBranches; i++)
|
||||||
|
free(bank[i].accounts);
|
||||||
|
free(bank);
|
||||||
|
nBranches = nAccounts = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long int withdraw(int branchNr, int accountNr, long int value) {
|
||||||
|
int rv, tmp;
|
||||||
|
rv = 0;
|
||||||
|
tmp = bank[branchNr].accounts[accountNr].balance - value;
|
||||||
|
if (tmp >= 0) {
|
||||||
|
bank[branchNr].accounts[accountNr].balance = tmp;
|
||||||
|
rv = value;
|
||||||
|
};
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deposit(int branchNr, int accountNr, long int value) {
|
||||||
|
bank[branchNr].accounts[accountNr].balance += value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer(int fromB, int toB, int accountNr, long int value) {
|
||||||
|
int money = withdraw(fromB, accountNr, value);
|
||||||
|
deposit(toB, accountNr, money);
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkAssets(void) {
|
||||||
|
static long assets = 0;
|
||||||
|
long int sum = 0;
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
for (int j = 0; j < nAccounts; j++) {
|
||||||
|
sum += (long int)bank[i].accounts[j].balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (assets == 0) {
|
||||||
|
assets = sum;
|
||||||
|
printf("Balance of accounts is: %ld\n", sum);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (sum != assets) {
|
||||||
|
printf("Balance of accounts is: %ld ... not correct\n", sum);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf("Balance of accounts is: %ld ... correct\n", assets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int checkIBC(void) {
|
||||||
|
static long ibcError = 0;
|
||||||
|
long sum = 0;
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
pthread_mutex_lock(&bank[i].branchLock);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
for (int j = 0; j < nAccounts; j++) {
|
||||||
|
sum += (long)bank[i].accounts[j].balance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < nBranches; i++) {
|
||||||
|
pthread_mutex_unlock(&bank[i].branchLock);
|
||||||
|
}
|
||||||
|
if (ibcError == 0) ibcError = sum;
|
||||||
|
return (ibcError != sum);
|
||||||
|
}
|
||||||
|
//******************************************************************************
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: banking.h
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
// banking functions
|
||||||
|
|
||||||
|
void makeBank(int num_branches, int num_accounts);
|
||||||
|
void deleteBank(void);
|
||||||
|
|
||||||
|
long withdraw(int branch, int account, long int value) ;
|
||||||
|
void deposit(int branch, int account, long int value);
|
||||||
|
void transfer(int fromB, int toB, int account, long int value);
|
||||||
|
void checkAssets(void);
|
||||||
|
int checkIBC(void);
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: main.c
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: locking mechanisms
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "banking.h"
|
||||||
|
#include "mtimer.h"
|
||||||
|
#include "mrandom.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// constant values
|
||||||
|
|
||||||
|
#define MAX_THREADS 16
|
||||||
|
#define NUM_THREADS 5
|
||||||
|
|
||||||
|
#define TRANSFERS (16*1024*1024L)
|
||||||
|
#define ACCOUNTS (2048)
|
||||||
|
#define BRANCHES (128)
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// globals
|
||||||
|
|
||||||
|
int nThreads;
|
||||||
|
int ibc = 0;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// customers
|
||||||
|
|
||||||
|
void *pusher(void *arg) {
|
||||||
|
int idx = (int)(long)(arg);
|
||||||
|
mrand_t rand;
|
||||||
|
unsigned int seed = 17*idx;
|
||||||
|
mrandInit(seed, &rand);
|
||||||
|
int account, from, to, val;
|
||||||
|
int count = TRANSFERS / nThreads;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
account = (int)(mrandUInt(&rand) % ACCOUNTS);
|
||||||
|
from = (int)(mrandUInt(&rand) % BRANCHES);
|
||||||
|
to = (int)(mrandUInt(&rand) % BRANCHES);
|
||||||
|
val = (int)(mrandRange(1000, 100000, &rand));
|
||||||
|
transfer(from, to, account, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *checker(void *arg) {
|
||||||
|
for (int i = 0; i < 1000; i = i) {
|
||||||
|
ibc += checkIBC();
|
||||||
|
usleep(100*1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// main program
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
gtimer_t timer;
|
||||||
|
mrand_t ranvar;
|
||||||
|
long assets;
|
||||||
|
|
||||||
|
// thread id's
|
||||||
|
pthread_t th[MAX_THREADS];
|
||||||
|
|
||||||
|
// get number of threads or default
|
||||||
|
if (argc > 1)
|
||||||
|
nThreads = atoi(argv[1]);
|
||||||
|
else
|
||||||
|
nThreads = NUM_THREADS;
|
||||||
|
nThreads = (nThreads > MAX_THREADS) ? MAX_THREADS : nThreads;
|
||||||
|
|
||||||
|
mrandInit((MAX_THREADS + 1)*333, &ranvar);
|
||||||
|
|
||||||
|
printf("\nRunning %d threads\n", nThreads);
|
||||||
|
makeBank(BRANCHES, ACCOUNTS);
|
||||||
|
for (int i = 0; i < ACCOUNTS; i++)
|
||||||
|
deposit(0, i, mrandRange(10, 1000*1000, &ranvar));
|
||||||
|
checkAssets();
|
||||||
|
|
||||||
|
startGTimer(timer);
|
||||||
|
// create threads and pass thread number
|
||||||
|
pthread_create(&th[0], NULL, checker, (void *)0);
|
||||||
|
sleep(1);
|
||||||
|
for (long i = 1; i < nThreads; i++)
|
||||||
|
pthread_create(&th[i], NULL, pusher, (void *)i);
|
||||||
|
// wait for threads to terminate
|
||||||
|
for (int i = 1; i < nThreads; i++)
|
||||||
|
pthread_join(th[i], NULL);
|
||||||
|
stopGTimer(timer);
|
||||||
|
|
||||||
|
checkAssets();
|
||||||
|
printGTime(timer);
|
||||||
|
|
||||||
|
if (ibc)
|
||||||
|
printf("\n\033[41mYou do not comply with the IBC rules \033[0m\n\n");
|
||||||
|
else
|
||||||
|
printf("\n\033[42mYou do comply with the IBC rules \033[0m\n\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,32 @@
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Makefile
|
||||||
|
# Course: BSy
|
||||||
|
# Date: M. Thaler, 1/2016
|
||||||
|
# File: makefile
|
||||||
|
# Version: v.fs20
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
#macros
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLGS = -std=gnu99
|
||||||
|
LIBS = -pthread
|
||||||
|
OFILES = main.o banking.o
|
||||||
|
HFILES = banking.h
|
||||||
|
|
||||||
|
main: $(OFILES) $(HFILES)
|
||||||
|
$(CC) $(CFLGS) $(LIBS) $(OFILES) -o $@.e
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(CFLGS) -c $<
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
$(CC) $(CFLGS) -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.e
|
||||||
|
@echo "directory cleaned"
|
||||||
|
|
||||||
|
all:
|
||||||
|
@rm -f *.o
|
||||||
|
make --no-print-directory main
|
||||||
|
#-----------------------------------------------------------------------------
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef MY_RANDOMGENERATOR_DEFINITIONS
|
||||||
|
#define MY_RANDOMGENERATOR_DEFINITIONS
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// Course: BSy
|
||||||
|
// File: mrandom.h
|
||||||
|
// Author: M. Thaler, ZHAW
|
||||||
|
// Purpose: thread safe random functions (reentrant)
|
||||||
|
// Version: v.fs20
|
||||||
|
//******************************************************************************
|
||||||
|
// date type: mrand_t
|
||||||
|
//
|
||||||
|
// functions:
|
||||||
|
// - void mrandInit(mrand_t *mrt) -> initialize with fixed seed
|
||||||
|
// - unsigned int mrandUInt(mrand_t *mrt) -> unsigned random number
|
||||||
|
// - unsigned int mrandRange(int low, int high, mrand_t *mrt)
|
||||||
|
// -> random number within range
|
||||||
|
//
|
||||||
|
/******************************************************************************/
|
||||||
|
// constanst for ecuyer generator: length approx 8 x 10^12
|
||||||
|
|
||||||
|
#define M1 2147483563
|
||||||
|
#define M2 2147483399
|
||||||
|
#define A1 40014
|
||||||
|
#define A2 40692
|
||||||
|
#define Q1 53668
|
||||||
|
#define Q2 52774
|
||||||
|
#define R1 12211
|
||||||
|
#define R2 3791
|
||||||
|
#define MRAND_MAX M1-1
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
typedef struct mrand_t { unsigned int s1; \
|
||||||
|
unsigned int s2; } mrand_t;
|
||||||
|
|
||||||
|
void mrandInit(unsigned int seed, mrand_t *mrt) {
|
||||||
|
mrt->s1 = 33777 + seed * 777;
|
||||||
|
mrt->s2 = 9777572 + seed * 33775;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mrandUInt(mrand_t *mrt) {
|
||||||
|
unsigned int rv;
|
||||||
|
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
|
||||||
|
if (mrt->s1 <= 0) mrt->s1 += M1;
|
||||||
|
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
|
||||||
|
if (mrt->s2 <= 0) mrt->s2 += M2;
|
||||||
|
rv = (mrt->s1 + mrt->s2) % M1;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mrandDouble(mrand_t *mrt) {
|
||||||
|
unsigned int rv;
|
||||||
|
double dv;
|
||||||
|
mrt->s1 = A1 * (mrt->s1 % Q1) - mrt->s1 * (mrt->s1/Q1);
|
||||||
|
if (mrt->s1 <= 0) mrt->s1 += M1;
|
||||||
|
mrt->s2 = A2 * (mrt->s2 % Q2) - mrt->s2 * (mrt->s2/Q2);
|
||||||
|
if (mrt->s2 <= 0) mrt->s2 += M2;
|
||||||
|
rv = (mrt->s1 + mrt->s2) % M1;
|
||||||
|
dv = (double)rv / ((double)(M1-1));
|
||||||
|
return dv;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int mrandRange(unsigned int low, unsigned int high, mrand_t *mrt) {
|
||||||
|
assert(low <= high);
|
||||||
|
double drv = mrandDouble(mrt);
|
||||||
|
unsigned int av = (unsigned int)(drv * (double)(high-low) + 0.5);
|
||||||
|
return low + av;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
#endif
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef TIMER_MACRO_DEFINITIONS
|
||||||
|
#define TIMER_MACRO_DEFINITIONS
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
// Course: BSy
|
||||||
|
// File: mtimer.h
|
||||||
|
// Purpose: timer functions gettimeofday()
|
||||||
|
// Author: M. Thaler, ZHAW, 1/2016
|
||||||
|
// Version: v.fs20
|
||||||
|
/******************************************************************************/
|
||||||
|
// gettimeofday()
|
||||||
|
// function: elapsed time: between start and stop
|
||||||
|
// data type: gtimer_t
|
||||||
|
// functions: startGTimer(gtimer_t tdata) -> start timer
|
||||||
|
// stopGTimer(gtimer_t tdata) -> stop timer
|
||||||
|
// double getWallGTime(gtimer_t tdata) -> get time in s
|
||||||
|
// printGTime(X) -> print time in s
|
||||||
|
//
|
||||||
|
// -> see also "man gettimeofday"
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/times.h>
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
typedef struct gtimer_t { struct timeval sT; \
|
||||||
|
struct timeval eT; } gtimer_t;
|
||||||
|
|
||||||
|
#define startGTimer(X) gettimeofday(&X.sT, NULL)
|
||||||
|
#define stopGTimer(X) gettimeofday(&X.eT, NULL)
|
||||||
|
#define getGTime(X) ((double)(X.eT.tv_sec) - (double)(X.sT.tv_sec)) +\
|
||||||
|
((double)X.eT.tv_usec - (double)X.sT.tv_usec)/1e6
|
||||||
|
#define printGTime(X) printf("Run time %3.2lfs\n", getGTime(X))
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
./main.e 1
|
||||||
|
./main.e 2
|
||||||
|
./main.e 4
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: coffeTeller.c
|
||||||
|
* Purpose: simple sequence with semaphores
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
sem_t *coin, *coffee, *ready;
|
||||||
|
|
||||||
|
// set up a semaphore
|
||||||
|
coin = sem_open(COIN_SEMAPHOR, 0);
|
||||||
|
coffee = sem_open(COFFEE_SEMAPHOR, 0);
|
||||||
|
ready = sem_open(READY_SEMAPHOR, 0);
|
||||||
|
|
||||||
|
// start teller machine
|
||||||
|
printf("\nCoffee teller machine starting\n\n");
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < ITERS) {
|
||||||
|
printf("teller (%d): waiting for coin\n", i);
|
||||||
|
printf(" (%d): got coin\n", i);
|
||||||
|
printf(" (%d): dispense coffee\n", i);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef MY_DEFINITIONS_HEADER
|
||||||
|
#define MY_DEFINITIONS_HEADER
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: commonDefs.h
|
||||||
|
* Purpose: common definitions
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013, 4/2014
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#define MYTURN_SEMAPHOR "/my_semaphor_1_name_simple_seq"
|
||||||
|
#define COIN_SEMAPHOR "/my_semaphor_2_name_simple_seq"
|
||||||
|
#define COFFEE_SEMAPHOR "/my_semaphor_3_name_simple_seq"
|
||||||
|
#define READY_SEMAPHOR "/my_semaphor_4_name_simple_seq"
|
||||||
|
|
||||||
|
#define ITERS (100*1000*1000)
|
||||||
|
#define CUSTOMERS 4
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#define checkSem(X) {if (X == SEM_FAILED) {perror("sem_open"); exit(-1);}}
|
||||||
|
|
||||||
|
#define drinkingCoffee(X) {usleep((((1+X)*rand())+100000)&0xFFFFF);}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: customer.c
|
||||||
|
* Purpose: simple sequence with semaphores
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
int i, myID;
|
||||||
|
sem_t *myTurn, *coin, *coffee, *ready;
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
myID = atoi(argv[1]);
|
||||||
|
else
|
||||||
|
myID = 0;
|
||||||
|
|
||||||
|
// set up a semaphore
|
||||||
|
myTurn = sem_open(MYTURN_SEMAPHOR, 0);
|
||||||
|
coin = sem_open(COIN_SEMAPHOR, 0);
|
||||||
|
coffee = sem_open(COFFEE_SEMAPHOR, 0);
|
||||||
|
ready = sem_open(READY_SEMAPHOR, 0);
|
||||||
|
|
||||||
|
// start customer
|
||||||
|
printf("Customer starting (%d)\n", myID);
|
||||||
|
|
||||||
|
// now check the sum
|
||||||
|
for (i = 0; i < ITERS; i++) {
|
||||||
|
printf("\t\t\t\tcustomer(%d) put coin %d\n", myID, i);
|
||||||
|
printf("\t\t\t\tcustomer(%d) waiting for coffee %d\n", myID, i);
|
||||||
|
printf("\t\t\t\tcustomer(%d) got coffee %d\n", myID, i);
|
||||||
|
drinkingCoffee(myID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Author M. Thaler InIT/ZHAW
|
||||||
|
# Version v.fs20
|
||||||
|
|
||||||
|
CMP= gcc -std=gnu99
|
||||||
|
CMPFLAGS= -Wall -g
|
||||||
|
LIB= -pthread
|
||||||
|
EXENAME0= startApp.e
|
||||||
|
EXENAME1= coffeeTeller.e
|
||||||
|
EXENAME2= customer.e
|
||||||
|
|
||||||
|
doit:
|
||||||
|
@make --no-print-directory clean
|
||||||
|
@make --no-print-directory startApp
|
||||||
|
@make --no-print-directory coffeeTeller
|
||||||
|
@make --no-print-directory customer
|
||||||
|
|
||||||
|
startApp: startApp.o
|
||||||
|
$(CMP) $(CMPFLAGS) startApp.o $(LIB) -o $(EXENAME0)
|
||||||
|
|
||||||
|
coffeeTeller: coffeeTeller.o
|
||||||
|
$(CMP) $(CMPFLAGS) coffeeTeller.o $(LIB) -o $(EXENAME1)
|
||||||
|
|
||||||
|
customer: customer.o
|
||||||
|
$(CMP) $(CMPFLAGS) customer.o $(LIB) -o $(EXENAME2)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CMP) -c $(CMPFLAGS) $<
|
||||||
|
|
||||||
|
.cc.o:
|
||||||
|
$(CMP) -c $(CMPFLAGS) $<
|
||||||
|
|
||||||
|
all:
|
||||||
|
@make clean
|
||||||
|
make doit
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f *.e *.o
|
||||||
|
|
||||||
|
purge:
|
||||||
|
@make clean
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: startApp.c
|
||||||
|
* Purpose: ice cream teller, basic sequence
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012, 7/2013
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
int j;
|
||||||
|
char string[8];
|
||||||
|
sem_t *myTurn, *coin, *coffee, *ready;
|
||||||
|
pid_t tellerPID;
|
||||||
|
|
||||||
|
sem_unlink(MYTURN_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
sem_unlink(COIN_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
sem_unlink(COFFEE_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
sem_unlink(READY_SEMAPHOR); // delete seamphor if it still exists
|
||||||
|
|
||||||
|
// set up a semaphore (? -> initial value of semaphor)
|
||||||
|
// checkSem() -> macro defined in commonDefs.h
|
||||||
|
|
||||||
|
/*
|
||||||
|
myTurn = sem_open(MYTURN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(myTurn);
|
||||||
|
coin = sem_open(COIN_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coin);
|
||||||
|
coffee = sem_open(COFFEE_SEMAPHOR, O_CREAT, 0700, ?); checkSem(coffee);
|
||||||
|
ready = sem_open(READY_SEMAPHOR, O_CREAT, 0700, ?); checkSem(ready);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// now that the resources are set up, the supervisor can be started
|
||||||
|
for (j = 1; j <= CUSTOMERS; j++) {
|
||||||
|
if (fork() == 0) {
|
||||||
|
sprintf(string, "%d", j);
|
||||||
|
execl("./customer.e", "customer.e", string, NULL);
|
||||||
|
printf("*** could not start customer.e ***\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tellerPID = fork()) == 0) {
|
||||||
|
execl("./coffeeTeller.e", "coffeeTeller.e", "0", NULL);
|
||||||
|
printf("*** could not start coffeTeller ***\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
waitpid(tellerPID, NULL, 0);
|
||||||
|
system("killall coffeeTeller.e");
|
||||||
|
system("killall customer.e"); // kill all customers
|
||||||
|
|
||||||
|
// clean up resources
|
||||||
|
sem_unlink(MYTURN_SEMAPHOR);
|
||||||
|
sem_unlink(COIN_SEMAPHOR);
|
||||||
|
sem_unlink(COFFEE_SEMAPHOR);
|
||||||
|
sem_unlink(READY_SEMAPHOR);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#******************************************************************************
|
||||||
|
# Purpose: turn off all CPU's but one (CPU 0), turn on all CPU's
|
||||||
|
# Linux only
|
||||||
|
# Author: M. Thaler, BSy 4/2014
|
||||||
|
|
||||||
|
# Usage: multiCPUs off: turn off all CPUs but one
|
||||||
|
# multiCPUs on: turn all CPUs on
|
||||||
|
#
|
||||||
|
# Version: v.fs20
|
||||||
|
#******************************************************************************
|
||||||
|
|
||||||
|
theDir="/sys/devices/system/cpu"
|
||||||
|
|
||||||
|
# check if sys exists
|
||||||
|
if test ! -d $theDir
|
||||||
|
then
|
||||||
|
echo "*** cannot set to single CPU ***"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# figure out what to do: multi CPUs off (single CPU) or all CPU's on
|
||||||
|
let status=1
|
||||||
|
if test "$1" = "on"
|
||||||
|
then
|
||||||
|
let status=1
|
||||||
|
else
|
||||||
|
if test "$1" = "off"
|
||||||
|
then
|
||||||
|
let status=0
|
||||||
|
else
|
||||||
|
echo "*** what do you want: ... on or off? ***"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# turn CPU's on or off
|
||||||
|
|
||||||
|
cd $theDir
|
||||||
|
|
||||||
|
CPUs=`ls -d cpu* | grep 'cpu[0-9][0-9]*'`
|
||||||
|
for CPU in $CPUs
|
||||||
|
do
|
||||||
|
if test ! "$CPU" = "cpu0"
|
||||||
|
then
|
||||||
|
echo "$CPU on = $status"
|
||||||
|
currVal=`cat ./$CPU/online`
|
||||||
|
# only change if different ... avoid error message
|
||||||
|
if test ! "$currVal" = "$status"
|
||||||
|
then
|
||||||
|
echo "$status" > "./$CPU/online"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
#******************************************************************************
|
|
@ -0,0 +1,7 @@
|
||||||
|
For Mac users
|
||||||
|
|
||||||
|
"pthread_mutex_lock(&lock)" is slow on MACs compared to Linux:
|
||||||
|
|
||||||
|
use instead: "while (pthread_mutex_trylock(&lock) > 0) {} ;"
|
||||||
|
|
||||||
|
which implements a spin lock
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: coffeTeller.c
|
||||||
|
* Purpose: coffe teller with pthreads
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
void *coffeeTeller(void* data) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
cData *cD = (cData *) data;
|
||||||
|
|
||||||
|
// now start selling coffee
|
||||||
|
printf("\nCoffee teller machine starting\n\n");
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < ITERATIONS) {
|
||||||
|
if (cD->coinCount != cD->selCount1 + cD->selCount2) {
|
||||||
|
printf("error c = %5d s1 =%6d s2 =%6d diff: %4d\ti = %d\n",
|
||||||
|
cD->coinCount, cD->selCount1, cD->selCount2,
|
||||||
|
cD->coinCount - cD->selCount1 - cD->selCount2,
|
||||||
|
i);
|
||||||
|
cD->coinCount = 0;
|
||||||
|
cD->selCount1 = cD->selCount2 = 0;
|
||||||
|
}
|
||||||
|
if (i%1000000 == 0) printf("working\n");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
|
@ -0,0 +1,17 @@
|
||||||
|
#ifndef MY_DEFINITIONS_TELLER_H
|
||||||
|
#define MY_DEFINITIONS_TELLER_H
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: coffeTeller.h
|
||||||
|
* Purpose: coffe teller with pthreads
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void *coffeeTeller(void* data);
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef MY_DEFINITIONS_HEADER
|
||||||
|
#define MY_DEFINITIONS_HEADER
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: commonDefs.h
|
||||||
|
* Purpose: header file for common definitions
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#define ITERATIONS (100*1000*1000)
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#define CUSTOMERS 4 // number of customers to be started
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// common data
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int coinCount; // number of paid coffees
|
||||||
|
int selCount1; // number of chosen coffees of type 1
|
||||||
|
int selCount2; // number of chosen coffees of type 2
|
||||||
|
pthread_mutex_t lock; // common lock
|
||||||
|
} cData;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: customer.c
|
||||||
|
* Purpose: customer thread
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
#include "mrand.h"
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
void *customer(void* data) {
|
||||||
|
float ranNum;
|
||||||
|
int i;
|
||||||
|
rand_t randnum;
|
||||||
|
|
||||||
|
cData *cD = (cData *) data;
|
||||||
|
|
||||||
|
rand_seed(&randnum, 0);
|
||||||
|
|
||||||
|
// put coin and select coffee
|
||||||
|
for (i = 0; i < ITERATIONS; i++) {
|
||||||
|
ranNum = rand_float(&randnum);
|
||||||
|
cD->coinCount += 1;
|
||||||
|
if (ranNum < 0.5)
|
||||||
|
cD->selCount1 += 1;
|
||||||
|
else
|
||||||
|
cD->selCount2 += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//*****************************************************************************
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef MY_DEFINITIONS_CUSTOMER_H
|
||||||
|
#define MY_DEFINITIONS_CUSTOMER_H
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: customer.h
|
||||||
|
* Purpose: customer thread
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
void *customer(void* data);
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
#endif
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Author M. Thaler
|
||||||
|
# Version v.fs20
|
||||||
|
|
||||||
|
CMP= gcc -std=gnu99
|
||||||
|
CMPFLAGS= -Wall -g
|
||||||
|
LIB= -pthread
|
||||||
|
EXENAME1= startApp.e
|
||||||
|
|
||||||
|
INCLS= commonDefs.h
|
||||||
|
FILES= startApp.o coffeeTeller.o customer.o
|
||||||
|
|
||||||
|
doit:
|
||||||
|
@make --no-print-directory clean
|
||||||
|
@make --no-print-directory coffeeTeller
|
||||||
|
|
||||||
|
coffeeTeller: $(FILES)
|
||||||
|
$(CMP) $(CMPFLAGS) $(FILES) $(LIB) -o $(EXENAME1)
|
||||||
|
|
||||||
|
.c.o: $(INCLS)
|
||||||
|
$(CMP) -c $(CMPFLAGS) $<
|
||||||
|
|
||||||
|
.cc.o: $(INCLS)
|
||||||
|
$(CMP) -c $(CMPFLAGS) $<
|
||||||
|
|
||||||
|
all:
|
||||||
|
@make clean
|
||||||
|
make doit
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f *.e *.o
|
||||||
|
|
||||||
|
purge:
|
||||||
|
@make clean
|
|
@ -0,0 +1,102 @@
|
||||||
|
#ifndef MY_THREADSAVE_RANDOM_GENERATOR
|
||||||
|
#define MY_THREADSAVE_RANDOM_GENERATOR
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* File: mrand.h
|
||||||
|
* Purpose: simple portable thread save random generator
|
||||||
|
* ccording to Schrage
|
||||||
|
* Author: M. Thaler, 5/2012, BSy
|
||||||
|
* Version: v.fs20
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#define MMM_MR 2147483563
|
||||||
|
#define AAA_MR 40014
|
||||||
|
#define QQQ_MR 53668
|
||||||
|
#define RRR_MR 12211
|
||||||
|
|
||||||
|
#define MRAND_MAX (MMM_MR-1)
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
typedef int rand_t;
|
||||||
|
|
||||||
|
// seed ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void rand_seed(rand_t *srand, int seed) {
|
||||||
|
struct timeval prandom_seed;
|
||||||
|
gettimeofday(&prandom_seed, NULL);
|
||||||
|
if (seed > 0)
|
||||||
|
*srand = seed;
|
||||||
|
else
|
||||||
|
*srand = (prandom_seed.tv_usec);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// integer random value -------------------------------------------------------
|
||||||
|
// range 0 .. MRAND_MAX (inclusive)
|
||||||
|
|
||||||
|
int rand_int(rand_t *srand) {
|
||||||
|
int nx;
|
||||||
|
nx = AAA_MR * (*srand % QQQ_MR) - RRR_MR * (*srand / QQQ_MR);
|
||||||
|
*srand = (nx > 0) ? nx : nx + MMM_MR;
|
||||||
|
return (*srand);
|
||||||
|
}
|
||||||
|
|
||||||
|
// float random value ---------------------------------------------------------
|
||||||
|
// range 0.0 .. 1.0 (inclusive)
|
||||||
|
|
||||||
|
float rand_float(rand_t *srand) {
|
||||||
|
float fx;
|
||||||
|
*srand = rand_int(srand);
|
||||||
|
fx = (float)(*srand) / ((float)MRAND_MAX);
|
||||||
|
return (fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// double random value --------------------------------------------------------
|
||||||
|
// range 0.0 .. 1.0 (inclusive)
|
||||||
|
|
||||||
|
double rand_double(rand_t *srand) {
|
||||||
|
double fx;
|
||||||
|
*srand = rand_int(srand);
|
||||||
|
fx = (double)(*srand) / ((double)MRAND_MAX);
|
||||||
|
return (fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsigned int random range --------------------------------------------------
|
||||||
|
// range low .. high
|
||||||
|
|
||||||
|
unsigned int rand_range(unsigned int low, unsigned int high, rand_t *srand) {
|
||||||
|
unsigned int rv;
|
||||||
|
double prop;
|
||||||
|
prop = ((double)(high - low)) * rand_double(srand);
|
||||||
|
rv = low + ((unsigned int) prop);
|
||||||
|
return(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsigned int probability ---------------------------------------------------
|
||||||
|
// returns 0 or 1
|
||||||
|
|
||||||
|
unsigned int rand_prob(double prob, rand_t *srand) {
|
||||||
|
if (rand_double(srand) >= 1.0-prob)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unsigned int toss coin -----------------------------------------------------
|
||||||
|
// returns 0 or 1
|
||||||
|
|
||||||
|
unsigned int toss_coin(rand_t *srand) {
|
||||||
|
if (rand_float(srand) >= 0.5)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* File: startApp.c
|
||||||
|
* Purpose: mutex with locks
|
||||||
|
* Course: bsy
|
||||||
|
* Author: M. Thaler, 2011
|
||||||
|
* Revision: 5/2012
|
||||||
|
* Version: v.fs20
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "commonDefs.h"
|
||||||
|
#include "coffeeTeller.h"
|
||||||
|
#include "customer.h"
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
// common data
|
||||||
|
|
||||||
|
cData cD;
|
||||||
|
|
||||||
|
//******************************************************************************
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
unsigned int j;
|
||||||
|
int pthr;
|
||||||
|
|
||||||
|
pthread_t tellerThread, customerThreads[CUSTOMERS];
|
||||||
|
|
||||||
|
cD.coinCount = 0;
|
||||||
|
cD.selCount1 = 0;
|
||||||
|
cD.selCount2 = 0;
|
||||||
|
pthread_mutex_init(&(cD.lock), NULL);
|
||||||
|
|
||||||
|
// start teller and customers now that everything is set up
|
||||||
|
pthr = pthread_create(&tellerThread, NULL, coffeeTeller, &cD);
|
||||||
|
assert(pthr == 0);
|
||||||
|
for (j = 0; j < CUSTOMERS; j++) {
|
||||||
|
pthr = pthread_create(&(customerThreads[j]), NULL, customer, &cD);
|
||||||
|
assert(pthr == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait for all threads to terminate
|
||||||
|
pthread_join(tellerThread, NULL);
|
||||||
|
|
||||||
|
for (j = 0; j < CUSTOMERS; j++) {
|
||||||
|
pthr = pthread_join(customerThreads[j], NULL);
|
||||||
|
assert(pthr == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//******************************************************************************
|
Loading…
Reference in New Issue