使用信号量的单通道桥同步
Single lane bridge Synchronization using semaphores
我正在尝试实现单通道桥同步问题。
一次,汽车只能朝一个方向行驶,而且桥梁的容量也是 5.I 下面想出了一些东西。
int curr_direction = -1;
//curr_direction values can be -1,1 and 2.-1 means bridge is empty
int cars_count = 0;
HANDLE sem_bridgempty;//To keep track whether the bridge is empty or not
HANDLE sem_bridgecount; //To keep track of count of cars on bridge
HANDLE mut_mutex;//For exclusive access
unsigned WINAPI enter(void *param)
{
int direction = *((int *)param);
WaitForSingleObject(mut_mutex,INFINITE);
if (curr_direction == -1)
curr_direction = direction;
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgecount, INFINITE);//Wait if more than 5 cars
WaitForSingleObject(mut_mutex, INFINITE);
if (direction == curr_direction)
{
cars_count++;
std::cout << "Car with direction " << direction << " entered " <<
GetCurrentThreadId() << std::endl;
ReleaseMutex(mut_mutex);
}
else
{
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgempty, INFINITE);//Wait for bridge to be empty so other direction car can enter
WaitForSingleObject(mut_mutex,INFINITE);
curr_direction = direction;
cars_count++;
std::cout << "Car with direction " << direction << " entered " << GetCurrentThreadId() << std::endl;
ReleaseMutex(mut_mutex);
}
return 0;
}
unsigned WINAPI exit(void *param)
{
WaitForSingleObject(mut_mutex, INFINITE);
cars_count--;
std::cout << "A Car exited " << GetCurrentThreadId() << std::endl;
ReleaseSemaphore(sem_bridgecount, 1, NULL);
if (cars_count == 0)
{
curr_direction = -1;
std::cout << "Bridge is empty " << GetCurrentThreadId() <<
std::endl;
ReleaseSemaphore(sem_bridgempty, 1, NULL);
}
ReleaseMutex(mut_mutex);
return 0;
}
int main()
{
sem_bridgecount = CreateSemaphore(NULL, 5, 5, NULL);
sem_bridgempty = CreateSemaphore(NULL, 0, 1, NULL);
sem_bridge_not_empty = CreateSemaphore(NULL, 0, 2, NULL);
mut_mutex = CreateMutex(NULL, false, NULL);
同步不work.When我测试这个我可以看到方向1
和2
的车同时进入。
else
{
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgempty, INFINITE); //line 1
WaitForSingleObject(mut_mutex, INFINITE);//line 2
假设方向为 2
的线程 1 正在等待 sem_bridge_empty
。
当桥变为空(direction=-1
)时,它在获取 mut_mutex
之前到达第 2.But 行,另一个方向为 1
的线程调用 enter
并看到 direction=-1
和 enters.Now 当控制在线程 1 处返回时,它也以 direction=2
进入,因为它忘记了另一个线程已经进入不同方向的事实。
我怎样才能使 mut_mutex
和 sem_bridge_empty
同步?
我想我会以不同的方式处理这个问题。
我看待问题的方式是更接近地模拟现实生活。
有一座桥。桥的每一端都有一个队列,汽车在那里等待进入。有一个agent(对应桥头的旗手)可以从队列中放车
一辆想要过桥的汽车(线程)创建一个事件,并将该事件放入队列中,以便在任何方向上过桥。然后它会在事件上休眠。当它到达队列的前面并且代理决定释放那辆车时,它将事件从队列中删除并发出信号。然后汽车继续过桥。当它到达另一端时,它通过执行 ReleaseSemaphore 通知它正在离开桥。
每个代理等待(我相信)三个因素:
- 方向==我的方向
- 桥上有空间
- 我的队列中至少有一辆车
发生这些情况时,它会从队列中释放一辆车,然后重复。
如果你想添加一点点缀,代理可以在其队列为空时释放其剩余时间片(或者可能仅当它保持空的时间超过一段时间)。
至少对我来说,这似乎更容易实现,而且更加现实。当桥改变方向时,我们不想随机选择五辆汽车让其通过——我们总是选择等待时间最长的汽车。
如果我们想让事情变得更加现实,我们可以将其设为双端队列而不是队列。紧急车辆(救护车、消防车等)将开到双端队列的前面而不是后面。当他们到达时,向另一个方向移动的车辆的计时器将立即到期(但他们仍然会等待桥上的车辆离开然后再进入)。
你的 WaitForSingleObject(mut_mutex)
不匹配 ReleaseMutex(mut_mutex)
计数 - 你(在输入中)为单个 WaitForSingleObject
调用 ReleaseMutex
2 或 3 次,这个已经很严重的错误。 if (direction == curr_direction)
已在同步部分之外调用 - 因此 curr_direction
可以随时更改。
正确的解决方案 - 检查和修改必须是 "atomic" 操作 - 在一些临界区内。所以将一些 cs 与桥相关联,这将保护它的状态。当汽车尝试进入桥时 - 进入此 cs 一次(!),决定汽车可以进入还是需要等待。退出 cs。如果需要等待 - 等待(当然在 cs 之外)。 mutex 也可以在这里使用,但是使用 cs 或 SRW 锁会更好 - 因为 mutex你每次都会进入内核进行同步。使用 cs - 仅在真正需要等待时使用。
你也没有考虑下一种情况 - if (direction == curr_direction)
你总是进入桥梁。但是如果对面的站点已经等了一些车怎么办?拳头进入桥的一侧(方向)可以无限握住它(假设无限车流朝这个方向),当另一个方向无限等待时。为了解决这个问题 - 需要添加一些 "traffic light" - 即使汽车在当前桥梁方向移动并在桥上自由存在 space - 它可以停下来等待,如果已经有汽车在对面等待。
还要注意如何将参数(方向)传递给线程 - 为什么通过指针而不是值?如果这是 C++ - 为什么不封装桥接逻辑(所有它的变量和同步对象在一些结构中?
我是select下一个解决方案(有统计数据):
struct Bridge : CRITICAL_SECTION
{
enum { MaxPositions = 3, MaxTransitsWhenOppositeWait = 1 };
HANDLE _hSemaphore[2];
ULONG _nWaitCount[2];
ULONG _nFreePositions, _nTransits;
LONG _direction;
//+++ statistic for test only
struct STAT {
ULONG _Exits[2];
ULONG _nWaitCount[2];
LONG _direction;
ULONG _CarsOnBridge;
} _stat[16];
ULONG _i_stat, _Exits[2], _nExits;
void CollectStat(LONG direction)
{
_Exits[direction]++;
if (!(++_nExits & 0xfff))// on every 0x1000*n exit save stat
{
if (_i_stat)
{
STAT *stat = &_stat[--_i_stat];
stat->_CarsOnBridge = MaxPositions - _nFreePositions;
stat->_direction = direction;
stat->_nWaitCount[0] = _nWaitCount[0];
stat->_nWaitCount[1] = _nWaitCount[1];
stat->_Exits[0] = _Exits[0];
stat->_Exits[1] = _Exits[1];
}
}
}
void DumpStat()
{
if (ULONG i = RTL_NUMBER_OF(_stat) - _i_stat)
{
do
{
STAT *stat = &_stat[_i_stat++];
DbgPrint("<(+%05u, -%05u) %c%u (+%u, -%u)>\n", stat->_Exits[0], stat->_Exits[1],
stat->_direction ? '-' : '+',
stat->_CarsOnBridge, stat->_nWaitCount[0], stat->_nWaitCount[1]);
} while (--i);
}
}
void InitStat()
{
RtlZeroMemory(_Exits, sizeof(_Exits)), _nExits = 0;
RtlZeroMemory(_stat, sizeof(_stat)), _i_stat = RTL_NUMBER_OF(_stat);
}
//--- statistic for test only
void Lock() { EnterCriticalSection(this); }
void Unlock() { LeaveCriticalSection(this); }
Bridge()
{
InitializeCriticalSection(this);
_hSemaphore[0] = 0, _hSemaphore[1] = 0;
_nWaitCount[0] = 0, _nWaitCount[1] = 0;
_nFreePositions = MaxPositions, _nTransits = MaxTransitsWhenOppositeWait, _direction = -1;
InitStat();
}
~Bridge()
{
DeleteCriticalSection(this);
if (_hSemaphore[1]) CloseHandle(_hSemaphore[1]);
if (_hSemaphore[0]) CloseHandle(_hSemaphore[0]);
if (_nWaitCount[0] || _nWaitCount[1] || _nFreePositions != MaxPositions)
{
__debugbreak();
}
DumpStat();
}
BOOL Create()
{
return (_hSemaphore[0] = CreateSemaphore(0, 0, MaxPositions, 0)) &&
(_hSemaphore[1] = CreateSemaphore(0, 0, MaxPositions, 0));
}
BOOL IsOppositeSideWaiting(LONG direction)
{
return _nWaitCount[1 - direction];
}
void EnterCars(LONG direction, ULONG n)
{
if (IsOppositeSideWaiting(direction))
{
_nTransits--;
}
_nFreePositions -= n;
}
void Enter(LONG direction)
{
BOOL bWait = FALSE;
Lock();
if (_direction < 0)
{
_direction = direction;
goto __m0;
}
else if (_direction == direction && _nFreePositions && _nTransits)
{
__m0:
EnterCars(direction, 1);
}
else
{
bWait = TRUE;
_nWaitCount[direction]++;
}
Unlock();
if (bWait)
{
if (WaitForSingleObject(_hSemaphore[direction], INFINITE) != WAIT_OBJECT_0)
{
__debugbreak();
}
}
}
void Exit(LONG direction)
{
if (_direction != direction)
{
__debugbreak();
}
Lock();
CollectStat(direction);
if (++_nFreePositions == MaxPositions)
{
// bridge is empty
_direction = -1, _nTransits = MaxTransitsWhenOppositeWait;
// change direction if opposite side wait
if (IsOppositeSideWaiting(direction))
{
direction = 1 - direction;
}
}
HANDLE hSemaphore = _hSemaphore[direction];
ULONG n = _nTransits ? min(_nWaitCount[direction], _nFreePositions) : 0;
if (n)
{
_direction = direction;
EnterCars(direction, n);
_nWaitCount[direction] -= n;
ReleaseSemaphore(hSemaphore, n, 0);
}
Unlock();
}
} g_Bridge;
ULONG car(LONG direction)
{
direction &= 1;// 0 or 1
WCHAR caption[16];
int i = 0x10000;// Number of transits
do
{
swprintf(caption, L"[%u] %08x", direction, GetCurrentThreadId());
//MessageBoxW(0, 0, caption, MB_OK);
SwitchToThread();// simulate wait
g_Bridge.Enter(direction);
SwitchToThread();// simulate wait
//MessageBoxW(0, 0, caption, direction ? MB_ICONWARNING : MB_ICONINFORMATION);
g_Bridge.Exit(direction);
direction = 1 - direction;// reverse direction
} while (--i);
return direction;//visible thread exit code in debug window
}
void SLBT()
{
if (g_Bridge.Create())
{
HANDLE hThreads[8], *phThread = hThreads, hThread;
ULONG n = RTL_NUMBER_OF(hThreads), m = 0;
do
{
if (hThread = CreateThread(0, PAGE_SIZE, (PTHREAD_START_ROUTINE)car, (PVOID)n, 0, 0))
{
*phThread++ = hThread, m++;
}
} while (--n);
if (m)
{
WaitForMultipleObjects(m, hThreads, TRUE, INFINITE);
do
{
CloseHandle(*--phThread);
} while (--m);
}
}
}
为了检查汽车如何在桥上行驶,我收集了每个 n*0x1000 个出口的一些统计数据。另请注意,在每个出口我都会检查方向是否正确:if (_direction != direction) __debugbreak();
一些统计输出:(每个方向有多少车通过桥,现在有多少车在桥上及其方向(+/-)。现在有多少车在等待)
<(+32768, -32768) +3 (+2, -3)>
<(+30720, -30720) -2 (+2, -3)>
<(+28672, -28672) +3 (+2, -3)>
<(+26625, -26623) +1 (+2, -5)>
<(+24576, -24576) -3 (+3, -2)>
<(+22529, -22527) +1 (+2, -5)>
<(+20480, -20480) +2 (+3, -2)>
<(+18432, -18432) +3 (+1, -3)>
<(+16385, -16383) +1 (+2, -3)>
<(+14335, -14337) -1 (+4, -2)>
<(+12288, -12288) +3 (+2, -3)>
<(+10239, -10241) -1 (+3, -2)>
<(+08192, -08192) +2 (+3, -3)>
<(+06143, -06145) -1 (+3, -2)>
<(+04096, -04096) +3 (+2, -3)>
<(+02048, -02048) +2 (+3, -3)>
您还可以取消注释消息框并减少 "manual" 模式下控制车的运输次数
例如enum { MaxPositions = 5, MaxTransitsWhenOppositeWait = 2 };
时的corse也可以用MaxPositions
和MaxTransitsWhenOppositeWait
玩
<(+32766, -32770) -1 (+7, -0)>
<(+30721, -30719) -5 (+0, -1)>
<(+28674, -28670) +1 (+0, -7)>
<(+26623, -26625) +5 (+2, -0)>
<(+24574, -24578) -1 (+7, -0)>
<(+22528, -22528) -5 (+0, -0)>
<(+20479, -20481) -3 (+2, -0)>
<(+18431, -18433) +5 (+2, -1)>
<(+16383, -16385) +5 (+2, -0)>
<(+14337, -14335) -5 (+0, -2)>
<(+12290, -12286) +1 (+0, -5)>
<(+10241, -10239) -5 (+0, -2)>
<(+08190, -08194) -1 (+7, -0)>
<(+06143, -06145) -2 (+3, -1)>
<(+04096, -04096) +5 (+0, -1)>
<(+02047, -02049) -3 (+1, -0)>
我正在尝试实现单通道桥同步问题。 一次,汽车只能朝一个方向行驶,而且桥梁的容量也是 5.I 下面想出了一些东西。
int curr_direction = -1;
//curr_direction values can be -1,1 and 2.-1 means bridge is empty
int cars_count = 0;
HANDLE sem_bridgempty;//To keep track whether the bridge is empty or not
HANDLE sem_bridgecount; //To keep track of count of cars on bridge
HANDLE mut_mutex;//For exclusive access
unsigned WINAPI enter(void *param)
{
int direction = *((int *)param);
WaitForSingleObject(mut_mutex,INFINITE);
if (curr_direction == -1)
curr_direction = direction;
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgecount, INFINITE);//Wait if more than 5 cars
WaitForSingleObject(mut_mutex, INFINITE);
if (direction == curr_direction)
{
cars_count++;
std::cout << "Car with direction " << direction << " entered " <<
GetCurrentThreadId() << std::endl;
ReleaseMutex(mut_mutex);
}
else
{
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgempty, INFINITE);//Wait for bridge to be empty so other direction car can enter
WaitForSingleObject(mut_mutex,INFINITE);
curr_direction = direction;
cars_count++;
std::cout << "Car with direction " << direction << " entered " << GetCurrentThreadId() << std::endl;
ReleaseMutex(mut_mutex);
}
return 0;
}
unsigned WINAPI exit(void *param)
{
WaitForSingleObject(mut_mutex, INFINITE);
cars_count--;
std::cout << "A Car exited " << GetCurrentThreadId() << std::endl;
ReleaseSemaphore(sem_bridgecount, 1, NULL);
if (cars_count == 0)
{
curr_direction = -1;
std::cout << "Bridge is empty " << GetCurrentThreadId() <<
std::endl;
ReleaseSemaphore(sem_bridgempty, 1, NULL);
}
ReleaseMutex(mut_mutex);
return 0;
}
int main()
{
sem_bridgecount = CreateSemaphore(NULL, 5, 5, NULL);
sem_bridgempty = CreateSemaphore(NULL, 0, 1, NULL);
sem_bridge_not_empty = CreateSemaphore(NULL, 0, 2, NULL);
mut_mutex = CreateMutex(NULL, false, NULL);
同步不work.When我测试这个我可以看到方向1
和2
的车同时进入。
else
{
ReleaseMutex(mut_mutex);
WaitForSingleObject(sem_bridgempty, INFINITE); //line 1
WaitForSingleObject(mut_mutex, INFINITE);//line 2
假设方向为 2
的线程 1 正在等待 sem_bridge_empty
。
当桥变为空(direction=-1
)时,它在获取 mut_mutex
之前到达第 2.But 行,另一个方向为 1
的线程调用 enter
并看到 direction=-1
和 enters.Now 当控制在线程 1 处返回时,它也以 direction=2
进入,因为它忘记了另一个线程已经进入不同方向的事实。
我怎样才能使 mut_mutex
和 sem_bridge_empty
同步?
我想我会以不同的方式处理这个问题。
我看待问题的方式是更接近地模拟现实生活。
有一座桥。桥的每一端都有一个队列,汽车在那里等待进入。有一个agent(对应桥头的旗手)可以从队列中放车
一辆想要过桥的汽车(线程)创建一个事件,并将该事件放入队列中,以便在任何方向上过桥。然后它会在事件上休眠。当它到达队列的前面并且代理决定释放那辆车时,它将事件从队列中删除并发出信号。然后汽车继续过桥。当它到达另一端时,它通过执行 ReleaseSemaphore 通知它正在离开桥。
每个代理等待(我相信)三个因素:
- 方向==我的方向
- 桥上有空间
- 我的队列中至少有一辆车
发生这些情况时,它会从队列中释放一辆车,然后重复。
如果你想添加一点点缀,代理可以在其队列为空时释放其剩余时间片(或者可能仅当它保持空的时间超过一段时间)。
至少对我来说,这似乎更容易实现,而且更加现实。当桥改变方向时,我们不想随机选择五辆汽车让其通过——我们总是选择等待时间最长的汽车。
如果我们想让事情变得更加现实,我们可以将其设为双端队列而不是队列。紧急车辆(救护车、消防车等)将开到双端队列的前面而不是后面。当他们到达时,向另一个方向移动的车辆的计时器将立即到期(但他们仍然会等待桥上的车辆离开然后再进入)。
你的 WaitForSingleObject(mut_mutex)
不匹配 ReleaseMutex(mut_mutex)
计数 - 你(在输入中)为单个 WaitForSingleObject
调用 ReleaseMutex
2 或 3 次,这个已经很严重的错误。 if (direction == curr_direction)
已在同步部分之外调用 - 因此 curr_direction
可以随时更改。
正确的解决方案 - 检查和修改必须是 "atomic" 操作 - 在一些临界区内。所以将一些 cs 与桥相关联,这将保护它的状态。当汽车尝试进入桥时 - 进入此 cs 一次(!),决定汽车可以进入还是需要等待。退出 cs。如果需要等待 - 等待(当然在 cs 之外)。 mutex 也可以在这里使用,但是使用 cs 或 SRW 锁会更好 - 因为 mutex你每次都会进入内核进行同步。使用 cs - 仅在真正需要等待时使用。
你也没有考虑下一种情况 - if (direction == curr_direction)
你总是进入桥梁。但是如果对面的站点已经等了一些车怎么办?拳头进入桥的一侧(方向)可以无限握住它(假设无限车流朝这个方向),当另一个方向无限等待时。为了解决这个问题 - 需要添加一些 "traffic light" - 即使汽车在当前桥梁方向移动并在桥上自由存在 space - 它可以停下来等待,如果已经有汽车在对面等待。
还要注意如何将参数(方向)传递给线程 - 为什么通过指针而不是值?如果这是 C++ - 为什么不封装桥接逻辑(所有它的变量和同步对象在一些结构中?
我是select下一个解决方案(有统计数据):
struct Bridge : CRITICAL_SECTION
{
enum { MaxPositions = 3, MaxTransitsWhenOppositeWait = 1 };
HANDLE _hSemaphore[2];
ULONG _nWaitCount[2];
ULONG _nFreePositions, _nTransits;
LONG _direction;
//+++ statistic for test only
struct STAT {
ULONG _Exits[2];
ULONG _nWaitCount[2];
LONG _direction;
ULONG _CarsOnBridge;
} _stat[16];
ULONG _i_stat, _Exits[2], _nExits;
void CollectStat(LONG direction)
{
_Exits[direction]++;
if (!(++_nExits & 0xfff))// on every 0x1000*n exit save stat
{
if (_i_stat)
{
STAT *stat = &_stat[--_i_stat];
stat->_CarsOnBridge = MaxPositions - _nFreePositions;
stat->_direction = direction;
stat->_nWaitCount[0] = _nWaitCount[0];
stat->_nWaitCount[1] = _nWaitCount[1];
stat->_Exits[0] = _Exits[0];
stat->_Exits[1] = _Exits[1];
}
}
}
void DumpStat()
{
if (ULONG i = RTL_NUMBER_OF(_stat) - _i_stat)
{
do
{
STAT *stat = &_stat[_i_stat++];
DbgPrint("<(+%05u, -%05u) %c%u (+%u, -%u)>\n", stat->_Exits[0], stat->_Exits[1],
stat->_direction ? '-' : '+',
stat->_CarsOnBridge, stat->_nWaitCount[0], stat->_nWaitCount[1]);
} while (--i);
}
}
void InitStat()
{
RtlZeroMemory(_Exits, sizeof(_Exits)), _nExits = 0;
RtlZeroMemory(_stat, sizeof(_stat)), _i_stat = RTL_NUMBER_OF(_stat);
}
//--- statistic for test only
void Lock() { EnterCriticalSection(this); }
void Unlock() { LeaveCriticalSection(this); }
Bridge()
{
InitializeCriticalSection(this);
_hSemaphore[0] = 0, _hSemaphore[1] = 0;
_nWaitCount[0] = 0, _nWaitCount[1] = 0;
_nFreePositions = MaxPositions, _nTransits = MaxTransitsWhenOppositeWait, _direction = -1;
InitStat();
}
~Bridge()
{
DeleteCriticalSection(this);
if (_hSemaphore[1]) CloseHandle(_hSemaphore[1]);
if (_hSemaphore[0]) CloseHandle(_hSemaphore[0]);
if (_nWaitCount[0] || _nWaitCount[1] || _nFreePositions != MaxPositions)
{
__debugbreak();
}
DumpStat();
}
BOOL Create()
{
return (_hSemaphore[0] = CreateSemaphore(0, 0, MaxPositions, 0)) &&
(_hSemaphore[1] = CreateSemaphore(0, 0, MaxPositions, 0));
}
BOOL IsOppositeSideWaiting(LONG direction)
{
return _nWaitCount[1 - direction];
}
void EnterCars(LONG direction, ULONG n)
{
if (IsOppositeSideWaiting(direction))
{
_nTransits--;
}
_nFreePositions -= n;
}
void Enter(LONG direction)
{
BOOL bWait = FALSE;
Lock();
if (_direction < 0)
{
_direction = direction;
goto __m0;
}
else if (_direction == direction && _nFreePositions && _nTransits)
{
__m0:
EnterCars(direction, 1);
}
else
{
bWait = TRUE;
_nWaitCount[direction]++;
}
Unlock();
if (bWait)
{
if (WaitForSingleObject(_hSemaphore[direction], INFINITE) != WAIT_OBJECT_0)
{
__debugbreak();
}
}
}
void Exit(LONG direction)
{
if (_direction != direction)
{
__debugbreak();
}
Lock();
CollectStat(direction);
if (++_nFreePositions == MaxPositions)
{
// bridge is empty
_direction = -1, _nTransits = MaxTransitsWhenOppositeWait;
// change direction if opposite side wait
if (IsOppositeSideWaiting(direction))
{
direction = 1 - direction;
}
}
HANDLE hSemaphore = _hSemaphore[direction];
ULONG n = _nTransits ? min(_nWaitCount[direction], _nFreePositions) : 0;
if (n)
{
_direction = direction;
EnterCars(direction, n);
_nWaitCount[direction] -= n;
ReleaseSemaphore(hSemaphore, n, 0);
}
Unlock();
}
} g_Bridge;
ULONG car(LONG direction)
{
direction &= 1;// 0 or 1
WCHAR caption[16];
int i = 0x10000;// Number of transits
do
{
swprintf(caption, L"[%u] %08x", direction, GetCurrentThreadId());
//MessageBoxW(0, 0, caption, MB_OK);
SwitchToThread();// simulate wait
g_Bridge.Enter(direction);
SwitchToThread();// simulate wait
//MessageBoxW(0, 0, caption, direction ? MB_ICONWARNING : MB_ICONINFORMATION);
g_Bridge.Exit(direction);
direction = 1 - direction;// reverse direction
} while (--i);
return direction;//visible thread exit code in debug window
}
void SLBT()
{
if (g_Bridge.Create())
{
HANDLE hThreads[8], *phThread = hThreads, hThread;
ULONG n = RTL_NUMBER_OF(hThreads), m = 0;
do
{
if (hThread = CreateThread(0, PAGE_SIZE, (PTHREAD_START_ROUTINE)car, (PVOID)n, 0, 0))
{
*phThread++ = hThread, m++;
}
} while (--n);
if (m)
{
WaitForMultipleObjects(m, hThreads, TRUE, INFINITE);
do
{
CloseHandle(*--phThread);
} while (--m);
}
}
}
为了检查汽车如何在桥上行驶,我收集了每个 n*0x1000 个出口的一些统计数据。另请注意,在每个出口我都会检查方向是否正确:if (_direction != direction) __debugbreak();
一些统计输出:(每个方向有多少车通过桥,现在有多少车在桥上及其方向(+/-)。现在有多少车在等待)
<(+32768, -32768) +3 (+2, -3)>
<(+30720, -30720) -2 (+2, -3)>
<(+28672, -28672) +3 (+2, -3)>
<(+26625, -26623) +1 (+2, -5)>
<(+24576, -24576) -3 (+3, -2)>
<(+22529, -22527) +1 (+2, -5)>
<(+20480, -20480) +2 (+3, -2)>
<(+18432, -18432) +3 (+1, -3)>
<(+16385, -16383) +1 (+2, -3)>
<(+14335, -14337) -1 (+4, -2)>
<(+12288, -12288) +3 (+2, -3)>
<(+10239, -10241) -1 (+3, -2)>
<(+08192, -08192) +2 (+3, -3)>
<(+06143, -06145) -1 (+3, -2)>
<(+04096, -04096) +3 (+2, -3)>
<(+02048, -02048) +2 (+3, -3)>
您还可以取消注释消息框并减少 "manual" 模式下控制车的运输次数
例如enum { MaxPositions = 5, MaxTransitsWhenOppositeWait = 2 };
时的corse也可以用MaxPositions
和MaxTransitsWhenOppositeWait
玩
<(+32766, -32770) -1 (+7, -0)>
<(+30721, -30719) -5 (+0, -1)>
<(+28674, -28670) +1 (+0, -7)>
<(+26623, -26625) +5 (+2, -0)>
<(+24574, -24578) -1 (+7, -0)>
<(+22528, -22528) -5 (+0, -0)>
<(+20479, -20481) -3 (+2, -0)>
<(+18431, -18433) +5 (+2, -1)>
<(+16383, -16385) +5 (+2, -0)>
<(+14337, -14335) -5 (+0, -2)>
<(+12290, -12286) +1 (+0, -5)>
<(+10241, -10239) -5 (+0, -2)>
<(+08190, -08194) -1 (+7, -0)>
<(+06143, -06145) -2 (+3, -1)>
<(+04096, -04096) +5 (+0, -1)>
<(+02047, -02049) -3 (+1, -0)>