C++ 线程和互斥
我正在做一个模拟加油站的程序。车站里的每辆车都有自己的线索。每辆车必须循环通过一个位掩码,以检查泵是否打开,如果打开,则更新位掩码,加注,并通知其他车泵现在已打开。我当前的代码可以工作,但负载平衡存在一些问题。理想情况下,所有泵的使用量相同,所有汽车的加油量相等 编辑:我的程序基本上需要一些汽车、水泵和一段时间来运行测试。在此期间,汽车将通过不断调用此函数来检查泵是否打开C++ 线程和互斥,c++,multithreading,mutex,locks,C++,Multithreading,Mutex,Locks,我正在做一个模拟加油站的程序。车站里的每辆车都有自己的线索。每辆车必须循环通过一个位掩码,以检查泵是否打开,如果打开,则更新位掩码,加注,并通知其他车泵现在已打开。我当前的代码可以工作,但负载平衡存在一些问题。理想情况下,所有泵的使用量相同,所有汽车的加油量相等 编辑:我的程序基本上需要一些汽车、水泵和一段时间来运行测试。在此期间,汽车将通过不断调用此函数来检查泵是否打开 int Station::fillUp() { // loop through the pumps using the b
int Station::fillUp()
{
// loop through the pumps using the bitmask to check if they are available
for (int i = 0; i < pumpsInStation; i++)
{
//Check bitmask to see if pump is open
stationMutex->lock();
if ((freeMask & (1 << i)) == 0 )
{
//Turning the bit on
freeMask |= (1 << i);
stationMutex->unlock();
// Sleeps thread for 30ms and increments counts
pumps[i].fillTankUp();
// Turning the bit back off
stationMutex->lock();
freeMask &= ~(1 << i);
stationCondition->notify_one();
stationMutex->unlock();
// Sleep long enough for all cars to have a chance to fill up first.
this_thread::sleep_for(std::chrono::milliseconds((((carsInStation-1) * 30) / pumpsInStation)-30));
return 1;
}
stationMutex->unlock();
}
// If not pumps are available, wait until one becomes available.
stationCondition->wait(std::unique_lock<std::mutex>(*stationMutex));
return -1;
}
int Station::fillUp()
{
//使用位掩码循环检查泵是否可用
对于(int i=0;ilock();
如果((自由掩码和(1锁)();
freeMask&=~(1 notify_one();
stationMutex->unlock();
//睡足够长的时间,让所有的车都有机会先加满油。
此线程::睡眠(std::chrono::毫秒(((carsInStation-1)*30)/泵安装-30));
返回1;
}
stationMutex->unlock();
}
//如果泵不可用,则等待一台可用。
stationCondition->wait(std::unique_lock(*stationMutex));
返回-1;
}
我觉得这个问题与读取时锁定位掩码有关。是否需要在if检查周围设置某种互斥或锁定?看起来每辆车都会首先检查泵0的可用性,如果泵忙,则会检查泵1,依此类推。鉴于此,我似乎期望泵0能够服务于most车型,其次是第二大车型的泵#1,一直到泵#(泵安装-1),只有在新车进站时所有泵同时使用的(相对罕见)情况下才会使用
如果您想获得更好的负载平衡,您可能应该让每辆车选择不同的随机顺序来迭代泵,而不是让它们都以相同的顺序检查泵的可用性。看起来每辆车都会先检查泵0的可用性,如果泵忙,则会检查泵1,依此类推n、 考虑到这一点,我似乎认为泵#0将服务于最多的汽车,其次是泵#1服务于第二多的汽车,一直到泵#(泵安装-1),它只有在(相对罕见的)情况下才能使用,即新车进站时所有泵都同时使用
如果您想获得更好的负载平衡,您可能应该让每辆车选择不同的随机顺序来迭代泵,而不是让它们都以相同的顺序检查泵的可用性。看起来每辆车都会先检查泵0的可用性,如果泵忙,则会检查泵1,依此类推n、 考虑到这一点,我似乎认为泵#0将服务于最多的汽车,其次是泵#1服务于第二多的汽车,一直到泵#(泵安装-1),它只有在(相对罕见的)情况下才能使用,即新车进站时所有泵都同时使用
如果您想获得更好的负载平衡,您可能应该让每辆车选择不同的随机顺序来迭代泵,而不是让它们都以相同的顺序检查泵的可用性。看起来每辆车都会先检查泵0的可用性,如果泵忙,则会检查泵1,依此类推n、 考虑到这一点,我似乎认为泵#0将服务于最多的汽车,其次是泵#1服务于第二多的汽车,一直到泵#(泵安装-1),它只有在(相对罕见的)情况下才能使用,即新车进站时所有泵都同时使用
如果您想获得更好的负载平衡,您可能应该让每辆车选择不同的随机顺序来迭代泵,而不是让它们都以相同的顺序检查泵的可用性。假设互斥锁有一个与之关联的队列,其中包含等待的线程。现在,您的一个线程成功地获取保护被占用站点位掩码的互斥锁,检查某个特定位置是否空闲。如果不是,它将再次释放互斥锁并循环,结果返回到等待互斥锁的线程队列的末尾。首先,这是不公平的,因为等待的第一个线程不能保证获得下一个空闲插槽,只有在该插槽发生时ns是其循环计数器上的一个。其次,它会导致大量的上下文切换,这对性能不利。请注意,您的方法仍应产生正确的结果,即在访问单个加油站时没有两辆车发生碰撞,但其行为是次优的 你应该做的是:
为了防止您不清楚这一部分,等待条件变量会在等待时隐式释放互斥体,然后重新获取它!假设互斥体有一个与之关联的队列,其中包含等待的线程。现在,您的一个线程设法获取保护已占用站点位掩码的互斥体,检查如果一个特定的位置是空闲的,如果它不是空闲的,它将再次释放互斥锁并循环,只返回到thr队列的末尾
int Station::acquirePump()
{
// loop through the pumps using the bitmask to check if they are available
ScopedLocker locker(&stationMutex);
for (int i = 0; i < pumpsInStation; i++)
{
// Check bitmask to see if pump is open
if ((freeMask & (1 << i)) == 0 )
{
//Turning the bit on
freeMask |= (1 << i);
return i;
}
}
return -1;
}
void Station::releasePump(int n)
{
ScopedLocker locker(&stationMutex);
freeMask &= ~(1 << n);
stationCondition->notify_one();
}
bool Station::fillUp()
{
// If a pump is available:
int i = acquirePump();
if (i != -1)
{
// Sleeps thread for 30ms and increments counts
pumps[i].fillTankUp();
releasePump(i)
// Sleep long enough for all cars to have a chance to fill up first.
this_thread::sleep_for(std::chrono::milliseconds((((carsInStation-1) * 30) / pumpsInStation)-30));
return true;
}
// If no pumps are available, wait until one becomes available.
stationCondition->wait(std::unique_lock<std::mutex>(*stationMutex));
return false;
}
int Station::acquirePump()
{
// loop through the pumps using the bitmask to check if they are available
ScopedLocker locker(&stationMutex);
for (int n = 0, i = startIndex; n < pumpsInStation; ++n, i = (i+1) % pumpsInStation)
{
// Check bitmask to see if pump is open
if ((freeMask & (1 << i)) == 0 )
{
// Change the starting index used to search for a free pump for
// the next car.
startIndex = (startIndex+1) % pumpsInStation;
// Turning the bit on
freeMask |= (1 << i);
return i;
}
}
return -1;
}