最后,我找到了一些时间来认真处理这个问题:
一般来说,我仍然难以理解您的实施。(在我回来之前,我花了几个小时首先了解了Edsger Dijkstra的银行家算法本身。)
因此,我不明白您为什么要区分need[]
和threadParams.req[]
。当我做对时,这实际上应该是相同的(即其中一个不应该在那里)。
但是,我想向您展示到目前为止我得到了什么(这可能会有所帮助)。在我研究并比较了多个样本之后,我终于在 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;
}
(在 VS2013 中调试但)在 Windows 10(64 位)的 cygwin 中使用 gcc 编译和测试:
$ 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.
$
这看起来相当不错(对我来说)。
现在,我制作了一个介绍多线程的派生示例。
关于此的注释:
Wikipedia 文章Banker's algorithm指出,该算法旨在用于操作系统资源管理,例如内存、信号量和接口访问。听起来对我来说,这些算法旨在管理诸如静音之类的东西。因此,互斥体应该/不能用于它,并且多线程没有多大意义。
但是,请忘记我的担忧,并说这是出于教育/理解目的:
#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;
}
(再次在 VS2013 中调试,但是)在 Windows 10(64 位)的 cygwin 中使用 gcc 编译和测试:
$ 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.
$
虽然,这看起来也不错,但我不确定死锁检测是否 100% 正确。因为多线程引入了不确定性,所以很难测试。我试图“用头调试它”,但结果头痛......
实施注意事项:
我再次将薄层用于多线程。因此,这些示例可以在 C++ ( std::thread
, VS2013/g++) 以及 C ( pthread
, gcc) 中编译。