I've been working on a bankers algorithm implementation in C and it seems to work fine except the allocation matrix isn't adding values correctly. In the request resources function, I use a mutex lock at the beginning and unlock right before returning a value to indicate pass or failure. In the function itself, the allocation matrix updates with what's been requested and given but when another thread comes in and does it's request, the allocation resets and starts adding again. I'm not sure why this is since allocation is global like the other structures being modified in the function and they are updating values properly.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>
/* these may be any values >= 0 */
#define NUMBER_OF_CUSTOMERS 5
#define NUMBER_OF_RESOURCES 3
/* the available amount of each resource */
int available[NUMBER_OF_RESOURCES];
/*the maximum demand of each customer */
int maximum[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES];
/* the amount currently allocated to each customer */
int allocation[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES];
/* the remaining need of each customer */
int need[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES];
pthread_mutex_t mutex =
PTHREAD_MUTEX_INITIALIZER;
struct threadParams {
int req[3];
int threadNum;
};
int safe_state(int customer_num){
int work[NUMBER_OF_RESOURCES];
int done =0;
for(int w = 0; w < NUMBER_OF_CUSTOMERS; w++){
work[w] = available[w];
}
int finish[NUMBER_OF_CUSTOMERS];
for(int i = 0; i < NUMBER_OF_CUSTOMERS; i++){
finish[i] = 0;
//setting finish to false
}
for(int k = 0; k < NUMBER_OF_CUSTOMERS; k++){
for(int j = 0; j< NUMBER_OF_RESOURCES; j++){
if(finish[k] == 0 && need[customer_num][k] <= work[j]){
work[j] += allocation[customer_num][j];
finish[k] = 1;
//printf("%d\n", finish[k]);
}
}
}
for(int x = 0; x < NUMBER_OF_CUSTOMERS; x++){
if(finish[x] == 1){
done = 1;
}
else{
done = -1;
}
}
if(done == 1){
printf("\n Granted\n");
return done;
}
printf("\nDenied\n");
return done;
}
void* request_resources(void *arg){
pthread_mutex_lock(&mutex);
struct threadParams *params = arg;
int customer_num = params->threadNum;
printf("\nCustomer %d is in critical\n", customer_num+1);
int request[3];
request[0] = params->req[0];
request[1] = params->req[1];
request[2] = params->req[2];
int pass;
for(int i = 0; i < NUMBER_OF_RESOURCES; i++){
if(request[i] <= need[customer_num][i] && request[i] <= available[i]){
//printf("\nreq: %d, need: %d, avail: %d, alloc: %d\n\t", request[i], need[customer_num][i], available[i],allocation[customer_num][i]);
int state = safe_state(customer_num);
if(state == 1){
available[i] -= request[i];
allocation[customer_num][i] += request[i];
//printf("%d + %d\n", allocation[customer_num][i], request[i]);
need[customer_num][i] -= request[i];
pass = 1;
}
else if(state == -1){
printf("\nThe request from customer %d results in unsafe state\n", customer_num+1);
printf("\nreq: %d, need: %d, avail: %d, alloc: %d\n\t", request[i], need[customer_num][i], available[i],allocation[customer_num][i]);
pass = -1;
break;
}
}
else{
printf("\nreq: %d, need: %d, avail: %d\n", request[i], need[customer_num][i], available[i]);
printf("\nNot enough resources for customer %d's request or the customer doesn't need this resource.\n", customer_num);
pass = -1;
break;
}
printf("\nResource: %d req: %d, need: %d, avail: %d, alloc: %d\n\t",i+1, request[i], need[customer_num][i], available[i],allocation[customer_num][i]);
}
//printf("I'm a thread\n");
pthread_mutex_unlock(&mutex);
printf("\n Customer %d has left critical\n", customer_num+1);
return pass;
}
int release_resources(int customer_num, int release[]){
}
int main(int argc, char *argv[]){
pthread_t threads [NUMBER_OF_CUSTOMERS];
int result;
unsigned index = 0;
// for(int ii = 0; ii < NUMBER_OF_CUSTOMERS; ii++){
// for(int jj = 0; jj < NUMBER_OF_RESOURCES; jj++){
// allocation[ii][jj] += 0;
// }
// }
for(index = 0; index < NUMBER_OF_RESOURCES; index++){
available[index] = strtol(argv[index+1], NULL,10);
}
for(int i = 0; i < NUMBER_OF_CUSTOMERS; i++){
for(int j = 0; j < NUMBER_OF_RESOURCES; j++){
maximum[i][j] = strtol(argv[j+1], NULL, 10)-4;
need[i][j] = 2; //strtol(argv[j+1], NULL, 10) - 6;
//printf("%d\t", maximum[i][j]);
}
}
for(index = 0; index < NUMBER_OF_CUSTOMERS; index++){
printf("\nCreating customer %d\n", index+1);
struct threadParams params;
params.req[0] = 2;
params.req[1] = 2;
params.req[2] = 2;
params.threadNum = index;
result = pthread_create(&threads[index],NULL,request_resources,¶ms);
}
for(index = 0; index < NUMBER_OF_CUSTOMERS; ++index){
pthread_join(threads[index], NULL);
}
printf("\nDone");
}
After I fixed some issues I got a running version:
#ifdef __cplusplus
#include <cstdio>
#include <cstdlib>
#include <mutex>
#include <thread>
using namespace std;
#else /* (not) __cplusplus */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#endif /* __cplusplus */
/* these may be any values >= 0 */
#define NUMBER_OF_CUSTOMERS 5
#define NUMBER_OF_RESOURCES 3
/* the available amount of each resource */
static int available[NUMBER_OF_RESOURCES];
/*the maximum demand of each customer */
static int maximum[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES];
/* the amount currently allocated to each customer */
static int allocation[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES];
/* the remaining need of each customer */
static int need[NUMBER_OF_CUSTOMERS][NUMBER_OF_RESOURCES];
struct ThreadParams {
int req[3];
int threadNum;
};
typedef void* (*PThreadFunc)(void*);
#ifdef __cplusplus
/* multi-threading thin layer for C++ and std::thread */
static mutex mtx;
static inline void lockMutex(mutex *pMtx) { pMtx->lock(); }
static inline void unlockMutex(mutex *pMtx) { pMtx->unlock(); }
typedef std::thread Thread;
static inline int startThread(
Thread *pThread,
void* (*pThreadFunc)(ThreadParams*), ThreadParams *pThreadParams)
{
return (*pThread = Thread(pThreadFunc, pThreadParams)).get_id()
== Thread::id();
/* thread creation failed -> thread id == thread::id() -> 1
* thread creation successful -> thread id != thread::id() -> 0
*/
}
static inline void joinThread(Thread *pThread) { pThread->join(); }
#else /* (not) __cplusplus */
/* multi-threading thin layer for C and pthread */
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static void lockMutex(pthread_mutex_t *pMtx)
{
pthread_mutex_lock(pMtx);
}
static void unlockMutex(pthread_mutex_t *pMtx)
{
pthread_mutex_unlock(pMtx);
}
typedef pthread_t Thread;
static int startThread(
Thread *pThread,
void* (*pThreadFunc)(struct ThreadParams*),
struct ThreadParams *pThreadParams)
{
return pthread_create(pThread, NULL,
(void*(*)(void*))pThreadFunc, pThreadParams);
}
static void joinThread(Thread *pThread) { pthread_join(*pThread, NULL); }
#endif /* __cplusplus */
static int safe_state(int customer_num)
{
int work[NUMBER_OF_RESOURCES];
for (int i = 0; i < NUMBER_OF_RESOURCES; ++i) {
work[i] = available[i];
}
int finish[NUMBER_OF_CUSTOMERS];
for(int i = 0; i < NUMBER_OF_CUSTOMERS; ++i) {
finish[i] = 0;
//setting finish to false
}
for (int k = 0; k < NUMBER_OF_CUSTOMERS; ++k) {
for (int j = 0; j < NUMBER_OF_RESOURCES; ++j) {
if (finish[k] == 0 && need[customer_num][k] <= work[j]) {
work[j] += allocation[customer_num][j];
finish[k] = 1;
//printf("%d\n", finish[k]);
}
}
}
int done = 0;
for (int x = 0; x < NUMBER_OF_CUSTOMERS; ++x) {
done = finish[x] ? 1 : -1;
}
if (done) printf("Granted\n");
else printf("Denied\n");
return done;
}
static void* request_resources(struct ThreadParams *params)
{
lockMutex(&mtx);
int customer_num = params->threadNum;
printf("Customer %d is in critical\n", customer_num+1);
int request[3];
request[0] = params->req[0];
request[1] = params->req[1];
request[2] = params->req[2];
int pass;
for (int i = 0; i < NUMBER_OF_RESOURCES; ++i) {
if (request[i] <= need[customer_num][i] && request[i] <= available[i]) {
//printf("\nreq: %d, need: %d, avail: %d, alloc: %d\n\t", request[i], need[customer_num][i], available[i],allocation[customer_num][i]);
int state = safe_state(customer_num);
if (state == 1) {
available[i] -= request[i];
allocation[customer_num][i] += request[i];
//printf("%d + %d\n", allocation[customer_num][i], request[i]);
need[customer_num][i] -= request[i];
pass = 1;
} else if (state == -1) {
printf("The request from customer %d results in unsafe state\n",
customer_num + 1);
printf("req: %d, need: %d, avail: %d, alloc: %d\n",
request[i], need[customer_num][i], available[i],
allocation[customer_num][i]);
pass = -1;
break;
}
} else {
printf("req: %d, need: %d, avail: %d\n",
request[i], need[customer_num][i], available[i]);
printf("Not enough resources for customer %d's request"
" or the customer doesn't need this resource.\n", customer_num);
pass = -1;
break;
}
printf("Resource: %d req: %d, need: %d, avail: %d, alloc: %d\n",
i + 1, request[i], need[customer_num][i], available[i],
allocation[customer_num][i]);
}
//printf("I'm a thread\n");
printf("Customer %d is about to left critical\n", customer_num + 1);
unlockMutex(&mtx);
return (void*)pass;
}
static int release_resources(int customer_num, int release[]) {
}
int main(int argc, char *argv[])
{
int input[NUMBER_OF_RESOURCES];
/* default input */
for (int i = 0; i < NUMBER_OF_RESOURCES; ++i) input[i] = 10;
/* override default input with command line arguments if provided */
if (argc > NUMBER_OF_RESOURCES) {
for (int i = 0; i < NUMBER_OF_RESOURCES; ++i) {
input[i] = strtol(argv[i + 1], NULL, 10);
}
}
int result;
// for(int ii = 0; ii < NUMBER_OF_CUSTOMERS; ii++){
// for(int jj = 0; jj < NUMBER_OF_RESOURCES; jj++){
// allocation[ii][jj] += 0;
// }
// }
for (int i = 0; i < NUMBER_OF_RESOURCES; ++i) {
available[i] = input[i];
}
for(int i = 0; i < NUMBER_OF_CUSTOMERS; ++i) {
for (int j = 0; j < NUMBER_OF_RESOURCES; ++j) {
maximum[i][j] = input[j] - 4;
need[i][j] = 2; //input[j] - 6;
//printf("%d\t", maximum[i][j]);
}
}
Thread threads[NUMBER_OF_CUSTOMERS];
struct ThreadParams params[NUMBER_OF_CUSTOMERS];
for (int i = 0; i < NUMBER_OF_CUSTOMERS; ++i) {
printf("Creating customer %d\n", i + 1);
params[i].req[0] = 2;
params[i].req[1] = 2;
params[i].req[2] = 2;
params[i].threadNum = i;
result = startThread(threads + i, &request_resources, params + i);
}
for (int i = 0; i < NUMBER_OF_CUSTOMERS; ++i) {
joinThread(threads + i);
}
printf("Done\n");
return 0;
}
Notes:
I was afraid of the life-time of struct threadParams param (in main()). Thus I made it an array and moved its declaration to a scope where it lives longer than the threads. (This was my first recommendation.)
A minor issue: I do not use post-fix inc./dec. if not necessary - a matter of taste.
I introduced some #ifdef __cplusplus and a thin-layer to be able to switch between pthread (C) and std::thread (C++). I did this to be able to compile and debug it in VS2013 with its nice debugger.
A minor issue: I prefixed all globals with static. I did this to prevent any potential issues with externs which might be declared in any header beyond my knowledge.
A minor issue: I provided some default values for missing command line arguments to simplify tests.
The VS2013 debugger uncovered another issue int work[NUMBER_OF_RESOURCES]; (in safe_state(), out of range access) which I fixed.
A minor issue: I re-formatted the output a little bit to make it more compact.
I compiled and tested it in VS2013 on Windows 10 (64 bit) and got this output (usage of std::thread):
Creating customer 1
Customer 1 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 8, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 8, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 8, alloc: 2
Customer 1 is about to left critical
Creating customer 2
Customer 2 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 6, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 6, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 6, alloc: 2
Customer 2 is about to left critical
Creating customer 3
Customer 3 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 4, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 4, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 4, alloc: 2
Customer 3 is about to left critical
Creating customer 4
Customer 4 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 2, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 2, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 2, alloc: 2
Customer 4 is about to left critical
Creating customer 5
Customer 5 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 0, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 0, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 0, alloc: 2
Customer 5 is about to left critical
Done
Drücken Sie eine beliebige Taste . . .
I compiled and tested it also with gcc on cygwin (using pthread):
$ gcc -std=c11 -x c bankers.cc -o bankers -pthread
$ ./bankers
Creating customer 1
Creating customer 2
Customer 1 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 8, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 8, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 8, alloc: 2
Customer 1 is about to left critical
Creating customer 3
Customer 2 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 6, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 6, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 6, alloc: 2
Customer 2 is about to left critical
Creating customer 4
Customer 3 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 4, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 4, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 4, alloc: 2
Customer 3 is about to left critical
Creating customer 5
Customer 4 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 2, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 2, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 2, alloc: 2
Customer 4 is about to left critical
Customer 5 is in critical
Granted
Resource: 1 req: 2, need: 0, avail: 0, alloc: 2
Granted
Resource: 2 req: 2, need: 0, avail: 0, alloc: 2
Granted
Resource: 3 req: 2, need: 0, avail: 0, alloc: 2
Customer 5 is about to left critical
Done
Finally, I found some time to handle this seriously:
I still have problems to understand your implementation in general. (I spent some hours to first understand Edsger Dijkstras Banker's algorithm itself before I came back.)
Thus, I do not understand why you distinguish need[] and threadParams.req[]. When I got it right this should actually be the same (i.e. one of them should not be there).
However, I want to show you what I got so far (which might be a help). After I studied and compared multiple samples I finally made a modified version of Banker's Algorithm on rosettacode.org:
#ifdef __cplusplus
#include <cassert>
#include <cstdio>
#include <cstring>
using namespace std;
#else /* (not) __cplusplus */
#include <assert.h>
#include <stdio.h>
#include <string.h>
#endif /* __cplusplus */
enum { nResources = 4 };
enum { nCustomers = 3 };
struct System {
/* the total amount of resources */
int total[nResources];
/* the available amount of each resource */
int available[nResources];
/* currently allocated resources */
int allocation[nCustomers][nResources];
/* the maximum demand of each customer */
int maximum[nCustomers][nResources];
};
static struct System testSetSafe1 = {
/* the total amount of resources */
{ 6, 5, 7, 6 },
/* the available amount of each resource */
{ },
/* currently allocated resources */
{
{ 1, 2, 2, 1 },
{ 1, 0, 3, 3 },
{ 1, 2, 1, 0 }
},
/* the maximum demand of each customer */
{
{ 3, 3, 2, 2 },
{ 1, 2, 3, 4 },
{ 1, 3, 5, 0 }
}
};
static struct System testSetSafe2 = {
/* the total amount of resources */
{ 6, 5, 7, 6 },
/* the available amount of each resource */
{ },
/* currently allocated resources */
{
{ 1, 0, 0, 1 },
{ 1, 0, 3, 3 },
{ 1, 2, 1, 0 }
},
/* the maximum demand of each customer */
{
{ 5, 3, 2, 2 },
{ 1, 2, 3, 4 },
{ 1, 3, 5, 0 }
}
};
static struct System testSetUnsafe = {
/* the total amount of resources */
{ 6, 5, 7, 6 },
/* the available amount of each resource */
{ },
/* currently allocated resources */
{
{ 1, 2, 2, 1 },
{ 1, 0, 3, 3 },
{ 1, 2, 1, 0 }
},
/* the maximum demand of each customer */
{
{ 5, 3, 2, 2 },
{ 1, 2, 3, 4 },
{ 1, 3, 5, 0 }
}
};
void initSystem(struct System *pSystem)
{
for (int j = 0; j < nResources; ++j) {
pSystem->available[j] = pSystem->total[j];
for (int i = 0; i < nCustomers; ++i) {
pSystem->available[j] -= pSystem->allocation[i][j];
}
}
}
void printR(const char *title, int table[nResources])
{
printf("%s:\n", title);
for (int j = 0; j < nResources; ++j) printf("\t%c", 'A' + j);
printf("\n");
for (int j = 0; j < nResources; ++j) printf("\t%d", table[j]);
printf("\n");
}
void printCR(const char *title, int table[nCustomers][nResources])
{
printf("%s:\n", title);
for (int j = 0; j < nResources; ++j) printf("\t%c", 'A' + j);
printf("\n");
for (int i = 0; i < nCustomers; ++i) {
printf("C%d", i + 1);
for (int j = 0; j < nResources; ++j) printf("\t%d", table[i][j]);
printf("\n");
}
}
int run(struct System *pSystem)
{
initSystem(pSystem);
printR("Total resources in system", pSystem->total);
printR("Available resources", pSystem->available);
printCR("Customers (currently allocated resources)",
pSystem->allocation);
printCR("Customers (maximum required resources", pSystem->maximum);
int running[nCustomers];
for (int count = nCustomers, safe; count;) {
safe = 0;
for (int i = 0; i < nCustomers; ++i) {
if (running[i]) {
int needed[nResources], blocked = 0;
for (int j = 0, block; j < nResources; ++j) {
needed[j]
= pSystem->maximum[i][j] - pSystem->allocation[i][j];
if ((block = needed[j] > pSystem->available[j])) {
printf("Customer %d blocked due to resource %c\n",
i + 1, 'A' + j);
}
blocked |= block;
}
if (!blocked) {
printf("Customer %d is served.\n", i + 1);
/* allocate resources */
for (int j = 0; j < nResources; ++j) {
pSystem->available[j] -= needed[j];
pSystem->allocation[i][j] += needed[j];
assert(pSystem->allocation[i][j] == pSystem->maximum[i][j]);
}
/* perform customer */
printR("Allocated resources", pSystem->allocation[i]);
running[i] = 0;
printf("Customer %d is done.\n", i + 1);
--count; /* customer finished */
safe = 1; /* processes still safe (no deadlock) */
/* free resources */
for (int j = 0; j < nResources; ++j) {
pSystem->available[j] += pSystem->allocation[i][j];
pSystem->allocation[i][j] = 0;
}
break; /* bail out of inner loop */
}
}
}
if (!safe) {
printf("Unsafe state (i.e. dead lock).\n");
printR("Total resources in system", pSystem->total);
printR("Available resources", pSystem->available);
printCR("Customers (currently allocated resources)",
pSystem->allocation);
printCR("Customers (maximum required resources",
pSystem->maximum);
return -1;
}
printR("Available resources", pSystem->available);
}
return 0;
}
int main()
{
/* 1st try: all requests can be granted soon */
printf(
"1st Run:\n"
"========\n"
"\n");
run(&testSetSafe1);
printf("\n");
/* 2nd try: all requests can be granted by changing order */
printf("2nd Run:\n"
"========\n"
"\n");
run(&testSetSafe2);
printf("\n");
/* 3rd try: unsafe state */
printf("3rd Run:\n"
"========\n"
"\n");
run(&testSetUnsafe);
printf("\n");
/* done */
printf("Done.\n");
return 0;
}
(Debugged in VS2013 but) compiled and tested with gcc in cygwin on Windows 10 (64 bit):
$ gcc -std=c11 -x c bankers.cc -o bankers
$ ./bankers
1st Run:
========
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 1 1 2
Customers (currently allocated resources):
A B C D
C1 1 2 2 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 3 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Customer 1 is served.
Allocated resources:
A B C D
3 3 2 2
Customer 1 is done.
Available resources:
A B C D
4 3 3 3
Customer 2 is served.
Allocated resources:
A B C D
1 2 3 4
Customer 2 is done.
Available resources:
A B C D
5 3 6 6
Customer 3 is served.
Allocated resources:
A B C D
1 3 5 0
Customer 3 is done.
Available resources:
A B C D
6 5 7 6
2nd Run:
========
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 3 3 2
Customers (currently allocated resources):
A B C D
C1 1 0 0 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 5 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Customer 1 blocked due to resource A
Customer 2 is served.
Allocated resources:
A B C D
1 2 3 4
Customer 2 is done.
Available resources:
A B C D
4 3 6 5
Customer 1 is served.
Allocated resources:
A B C D
5 3 2 2
Customer 1 is done.
Available resources:
A B C D
5 3 6 6
Customer 3 is served.
Allocated resources:
A B C D
1 3 5 0
Customer 3 is done.
Available resources:
A B C D
6 5 7 6
3rd Run:
========
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 1 1 2
Customers (currently allocated resources):
A B C D
C1 1 2 2 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 5 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Customer 1 blocked due to resource A
Customer 2 blocked due to resource B
Customer 3 blocked due to resource C
Unsafe state (i.e. dead lock).
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 1 1 2
Customers (currently allocated resources):
A B C D
C1 1 2 2 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 5 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Done.
$
This looks quite good (for me).
Now, I made a derived sample introducing multi-threading.
A note about this:
The Wikipedia article Banker's algorithm states that the algorithm is intended for OS resource management like e.g. memory, semaphores and interface access. Sounds for me like, these algorithm is intended to manage things like muteces. Thus, a mutex should/can not be used for it and multi-threading makes not so much sense.
However, let forget about my concern and say this is for educational/understanding purpose:
#ifdef __cplusplus
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <mutex>
#include <thread>
using namespace std;
#else /* (not) __cplusplus */
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#endif /* __cplusplus */
enum { nResources = 4 };
enum { nCustomers = 3 };
struct System {
/* the total amount of resources */
int total[nResources];
/* the available amount of each resource */
int available[nResources];
/* currently allocated resources */
int allocation[nCustomers][nResources];
/* the maximum demand of each customer */
int maximum[nCustomers][nResources];
/* customers to serve, blocked customers */
int running, blocked;
};
static struct System testSetSafe1 = {
/* the total amount of resources */
{ 6, 5, 7, 6 },
/* the available amount of each resource */
{ },
/* currently allocated resources */
{
{ 1, 2, 2, 1 },
{ 1, 0, 3, 3 },
{ 1, 2, 1, 0 }
},
/* the maximum demand of each customer */
{
{ 3, 3, 2, 2 },
{ 1, 2, 3, 4 },
{ 1, 3, 5, 0 }
}
};
static struct System testSetSafe2 = {
/* the total amount of resources */
{ 6, 5, 7, 6 },
/* the available amount of each resource */
{ },
/* currently allocated resources */
{
{ 1, 0, 0, 1 },
{ 1, 0, 3, 3 },
{ 1, 2, 1, 0 }
},
/* the maximum demand of each customer */
{
{ 5, 3, 2, 2 },
{ 1, 2, 3, 4 },
{ 1, 3, 5, 0 }
}
};
static struct System testSetUnsafe = {
/* the total amount of resources */
{ 6, 5, 7, 6 },
/* the available amount of each resource */
{ },
/* currently allocated resources */
{
{ 1, 2, 2, 1 },
{ 1, 0, 3, 3 },
{ 1, 2, 1, 0 }
},
/* the maximum demand of each customer */
{
{ 5, 3, 2, 2 },
{ 1, 2, 3, 4 },
{ 1, 3, 5, 0 }
}
};
void initSystem(struct System *pSystem)
{
for (int j = 0; j < nResources; ++j) {
pSystem->available[j] = pSystem->total[j];
for (int i = 0; i < nCustomers; ++i) {
pSystem->available[j] -= pSystem->allocation[i][j];
}
}
pSystem->running = nCustomers; pSystem->blocked = 0;
}
void printR(const char *title, int table[nResources])
{
printf("%s:\n", title);
for (int j = 0; j < nResources; ++j) printf("\t%c", 'A' + j);
printf("\n");
for (int j = 0; j < nResources; ++j) printf("\t%d", table[j]);
printf("\n");
}
void printCR(const char *title, int table[nCustomers][nResources])
{
printf("%s:\n", title);
for (int j = 0; j < nResources; ++j) printf("\t%c", 'A' + j);
printf("\n");
for (int i = 0; i < nCustomers; ++i) {
printf("C%d", i + 1);
for (int j = 0; j < nResources; ++j) printf("\t%d", table[i][j]);
printf("\n");
}
}
struct Customer {
int i;
struct System *pSystem;
int blocked;
};
static void initCustomer(
struct Customer *pCustomer, int i, struct System *pSystem)
{
pCustomer->i = i;
pCustomer->pSystem = pSystem;
pCustomer->blocked = 0;
}
#ifdef __cplusplus
/* multi-threading thin layer for C++ and std::thread */
static mutex mtx;
static inline void lockMutex(mutex *pMtx) { pMtx->lock(); }
static inline void unlockMutex(mutex *pMtx) { pMtx->unlock(); }
typedef std::thread Thread;
static inline int startThread(
Thread *pThread,
void* (*pThreadFunc)(Customer*), Customer *pCustomer)
{
return (*pThread = Thread(pThreadFunc, pCustomer)).get_id()
== Thread::id();
/* thread creation failed -> thread id == thread::id() -> 1
* thread creation successful -> thread id != thread::id() -> 0
*/
}
static inline void joinThread(Thread *pThread) { pThread->join(); }
#else /* (not) __cplusplus */
/* multi-threading thin layer for C and pthread */
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static void lockMutex(pthread_mutex_t *pMtx)
{
pthread_mutex_lock(pMtx);
}
static void unlockMutex(pthread_mutex_t *pMtx)
{
pthread_mutex_unlock(pMtx);
}
typedef pthread_t Thread;
static int startThread(
Thread *pThread,
void* (*pThreadFunc)(struct Customer*),
struct Customer *pCustomer)
{
return pthread_create(pThread, NULL,
(void*(*)(void*))pThreadFunc, pCustomer);
}
static void joinThread(Thread *pThread) { pthread_join(*pThread, NULL); }
#endif /* __cplusplus */
void* runCustomer(struct Customer *pCustomer)
{
int i = pCustomer->i;
struct System *pSystem = pCustomer->pSystem;
int needed[nResources];
for (int j = 0; j < nResources; ++j) {
needed[j] = pSystem->maximum[i][j] - pSystem->allocation[i][j];
}
for (int done = 0; !done;) {
lockMutex(&mtx); /* thread-safe access to shared system */
if (pCustomer->blocked) --pSystem->blocked;
pCustomer->blocked = 0;
for (int j = 0, block; j < nResources; ++j) {
if ((block = needed[j] > pSystem->available[j])) {
printf("Customer %d blocked due to resource %c\n",
i + 1, 'A' + j);
}
pCustomer->blocked |= block;
}
if (!pCustomer->blocked) {
printf("Customer %d is served.\n", i + 1);
/* allocate resources */
for (int j = 0; j < nResources; ++j) {
pSystem->available[j] -= needed[j];
pSystem->allocation[i][j] += needed[j];
assert(pSystem->allocation[i][j] == pSystem->maximum[i][j]);
}
/* perform customer */
printR("Allocated resources", pSystem->allocation[i]);
--pSystem->running;
done = 1; /* customer finished */
printf("Customer %d is done.\n", i + 1);
/* free resources */
for (int j = 0; j < nResources; ++j) {
pSystem->available[j] += pSystem->allocation[i][j];
pSystem->allocation[i][j] = 0;
}
} else {
++pSystem->blocked;
if ((done = pSystem->running <= pSystem->blocked)) {
printf("Customer %d exited (due to dead-lock).\n", i + 1);
}
}
unlockMutex(&mtx);
}
return 0;
}
int run(struct System *pSystem)
{
initSystem(pSystem);
printR("Total resources in system", pSystem->total);
printR("Available resources", pSystem->available);
printCR("Customers (currently allocated resources)",
pSystem->allocation);
printCR("Customers (maximum required resources", pSystem->maximum);
/* created threads for customers */
lockMutex(&mtx); /* force concurrency a little bit */
Thread threads[nCustomers];
struct Customer customers[nCustomers];
for (int i = 0; i < nCustomers; ++i) {
printf("Creating customer %d\n", i + 1);
initCustomer(customers + i, i, pSystem);
if (startThread(threads + i, &runCustomer, customers + i)) {
printf("ERROR: Failed to start thread for customer %d!\n", i + 1);
}
}
/* unlock mutex to let threads compete */
printf("Ready, steady, go...\n");
unlockMutex(&mtx);
/* join all threads */
for (int i = 0; i < nCustomers; ++i) joinThread(threads + i);
/* report */
if (pSystem->blocked) {
printf("Unsafe state (i.e. dead lock).\n");
printR("Total resources in system", pSystem->total);
printR("Available resources", pSystem->available);
printCR("Customers (currently allocated resources)",
pSystem->allocation);
printCR("Customers (maximum required resources",
pSystem->maximum);
return -1;
}
return 0;
}
int main()
{
/* 1st try: all requests can be granted soon */
printf(
"1st Run:\n"
"========\n"
"\n");
run(&testSetSafe1);
printf("\n");
/* 2nd try: all requests can be granted by changing order */
printf("2nd Run:\n"
"========\n"
"\n");
run(&testSetSafe2);
printf("\n");
/* 3rd try: unsafe state */
printf("3rd Run:\n"
"========\n"
"\n");
run(&testSetUnsafe);
printf("\n");
/* done */
printf("Done.\n");
return 0;
}
(Again debugged in VS2013 but) compiled and tested with gcc in cygwin on Windows 10 (64 bit):
$ gcc -std=c11 -x c bankersMT.cc -o bankersMT -pthread
$ ./bankersMT
1st Run:
========
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 1 1 2
Customers (currently allocated resources):
A B C D
C1 1 2 2 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 3 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Creating customer 1
Creating customer 2
Creating customer 3
Ready, steady, go...
Customer 1 is served.
Allocated resources:
A B C D
3 3 2 2
Customer 1 is done.
Customer 2 is served.
Allocated resources:
A B C D
1 2 3 4
Customer 2 is done.
Customer 3 is served.
Allocated resources:
A B C D
1 3 5 0
Customer 3 is done.
2nd Run:
========
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 3 3 2
Customers (currently allocated resources):
A B C D
C1 1 0 0 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 5 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Creating customer 1
Creating customer 2
Creating customer 3
Ready, steady, go...
Customer 1 blocked due to resource A
Customer 2 is served.
Allocated resources:
A B C D
1 2 3 4
Customer 2 is done.
Customer 3 is served.
Allocated resources:
A B C D
1 3 5 0
Customer 3 is done.
Customer 1 is served.
Allocated resources:
A B C D
5 3 2 2
Customer 1 is done.
3rd Run:
========
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 1 1 2
Customers (currently allocated resources):
A B C D
C1 1 2 2 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 5 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Creating customer 1
Creating customer 2
Creating customer 3
Ready, steady, go...
Customer 1 blocked due to resource A
Customer 2 blocked due to resource B
Customer 3 blocked due to resource C
Customer 3 exited (due to dead-lock).
Customer 1 blocked due to resource A
Customer 1 exited (due to dead-lock).
Customer 2 blocked due to resource B
Customer 2 exited (due to dead-lock).
Unsafe state (i.e. dead lock).
Total resources in system:
A B C D
6 5 7 6
Available resources:
A B C D
3 1 1 2
Customers (currently allocated resources):
A B C D
C1 1 2 2 1
C2 1 0 3 3
C3 1 2 1 0
Customers (maximum required resources:
A B C D
C1 5 3 2 2
C2 1 2 3 4
C3 1 3 5 0
Done.
$
Although, this looks quite good also, I'm not sure about whether the dead-lock detection is 100 % correct. Because multi-threading introduces non-deterministics, this is hard to test. I tried to "debug it by head" but ended up with headache...
Note about implementation:
I used the thin-layer for multi-threading, again. Thus, these samples can be compiled in C++ (std::thread, VS2013/g++) as well as in C (pthread, gcc).
Here is my C sudoku solver using recursive backtracing, with help code from online. The program is small, and branches of the puzzle are stored on the stack and it moves forward adding new puzzle's, and if it fails to find a solution for a position it returns to the previous branch and continues.
While this works for finding 1 solution, I'm trying to adapt it to print every solution. Where the else clause /* SOLUTION FOUND AS NO MORE EMPTY BLOCKS! */ is what ends the function, I've tried returning as sudokuSolver() with various (rows,cols) but can't seem to get to continue correctly to print all solutions.
Code:
#include <stdio.h>
#include <string.h>
int isAvailable(int puzzle[][9], int row, int col, int num)
{
int rowStart = (row/3) * 3;
int colStart = (col/3) * 3;
int i, j;
for(i=0; i<9; ++i) {
if (puzzle[row][i] == num)
return 0;
if (puzzle[i][col] == num)
return 0;
if (puzzle[rowStart + (i%3)][colStart + (i/3)] == num)
return 0;
}
return 1;
}
int solveSudoku(int puzzle[][9], int row, int col)
{
int i;
if (row<9 && col<9) {
if(puzzle[row][col] != 0) {
if ((col+1) < 9)
return solveSudoku(puzzle, row, col+1);
else if ((row+1) < 9)
return solveSudoku(puzzle, row+1, 0);
else /*SOLUTION FOUND AS NO MORE EMPTY BLOCKS!*/
return 1;
}
else {
for(i=0; i<9; ++i) {
if(isAvailable(puzzle, row, col, i+1)) {
puzzle[row][col] = i+1;
if ((col+1) < 9){
if (solveSudoku(puzzle, row, col +1))
return 1;
else
puzzle[row][col] = 0;
}
else if ((row+1) < 9) {
if (solveSudoku(puzzle, row+1, 0))
return 1;
else
puzzle[row][col] = 0;
}
else
return 1;
}
}
}
return 0;
}
else {
return 1;
}
}
int main()
{
int sudoku_arr[9][9] = {
{8,0,0,6,0,0,9,0,5},
{0,0,0,0,0,0,0,0,0},
{0,0,0,0,2,0,3,1,0},
{0,0,7,3,1,8,0,6,0},
{2,4,0,0,0,0,0,7,3},
{0,0,0,0,0,0,0,0,0},
{0,0,2,7,9,0,1,0,0},
{5,0,0,0,8,0,0,3,6},
{0,0,3,0,0,0,0,0,0}
};
if (solveSudoku(sudoku_arr, 0, 0)) { //Solve sudoku puzzle
printf("\nSudoku solved:\n");
int row, col;
for(row=0; row<9; row++) {
for(col=0; col<9; col++) {
printf("%d ", sudoku_arr[row][col]);
}
printf("\n");
}
return 0;
}
else {
printf("\nNo sudoku solution");
return -1;
}
}
Now while this solves with the first solution:
Sudoku solved:
8 1 4 6 3 7 9 2 5
3 2 5 1 4 9 6 8 7
7 9 6 8 2 5 3 1 4
9 5 7 3 1 8 4 6 2
2 4 1 9 5 6 8 7 3
6 3 8 2 7 4 5 9 1
4 6 2 7 9 3 1 5 8
5 7 9 4 8 1 2 3 6
1 8 3 5 6 2 7 4 9
There are many other possible solutions i.e.
814637925325149687796825314957318462241956873638274591462793158579481236183562749
814637925325941687796825314957318462241569873638472591462793158579184236183256749
834671925125839647796425318957318462241956873368247591682793154579184236413562789
834671925125839647796524318957318462241956873368247591682793154519482736473165289
834671925125839647796524318957318462241965873368247591682793154519482736473156289
The sudoku_arr is passed by reference. When you set a value inside solveSudoku () function, you are overwriting the original array and hence when it tries to backtrack, there are no more locations with 0 value on array.
What you really want to do is to reset the value to 0 in solveSudoku () before you return 1;.
Also, you would want to print the solution as soon as there are no empty locations left before returning.
This might be helpful.