我目前正在开发一个粒子系统,该系统使用一个线程,其中粒子首先更新,然后绘制。粒子存储在 std::vector
中。我想将更新功能移至单独的线程以提高系统性能。然而,这意味着当更新线程和绘制线程同时访问 std::vector 时我会遇到问题。我的更新函数将更改所有粒子的位置值和颜色,并且几乎总是调整std::vector
的大小。
单线程方法:
std::vector<Particle> particles;
void tick() //tick would be called from main update loop
{
//slow as must wait for update to draw
updateParticles();
drawParticles();
}
多线程:
std::vector<Particle> particles;
//quicker as no longer need to wait to draw and update
//crashes when both threads access the same data, or update resizes vector
void updateThread()
{
updateParticles();
}
void drawThread()
{
drawParticles();
}
为了解决这个问题,我使用 std::mutex
进行了研究,但在实践中,如果有大量粒子,线程的持续锁定意味着性能不会提高。我还研究了 std::atomic ,但是粒子和 std::vector 都不是可简单复制的,因此也不能使用它。
使用互斥体的多线程:
注意:我正在使用 SDL 互斥体,据我所知,原理是相同的。
SDL_mutex mutex = SDL_CreateMutex();
SDL_cond canDraw = SDL_CreateCond();
SDL_cond canUpdate = SDL_CreateCond();
std::vector<Particle> particles;
//locking the threads leads to the same problems as before,
//now each thread must wait for the other one
void updateThread()
{
SDL_LockMutex(lock);
while(!canUpdate)
{
SDL_CondWait(canUpdate, lock);
}
updateParticles();
SDL_UnlockMutex(lock);
SDL_CondSignal(canDraw);
}
void drawThread()
{
SDL_LockMutex(lock);
while(!canDraw)
{
SDL_CondWait(canDraw, lock);
}
drawParticles();
SDL_UnlockMutex(lock);
SDL_CondSignal(canUpdate);
}
我想知道是否还有其他方法可以实现多线程方法?本质上是防止两个线程同时访问相同的数据,而不必让每个线程等待另一个线程。我曾考虑过制作要从中绘制的 vector 的本地拷贝,但这似乎效率低下,并且如果更新线程在复制 vector 时更改 vector ,可能会遇到相同的问题?
最佳答案
我会使用更细粒度的锁定策略。我不会在您的 vector
中存储粒子
对象,而是存储一个指向不同对象的指针。
结构锁定粒子{
粒子*包含的粒子;
SDL_mutex 锁定对象;
};
在 updateParticles()
中,我将尝试使用 SDL_TryLockMutex()
获取各个锁定对象 - 如果我无法获得互斥体的控制权,我会将指针添加到将此特定的 lockedParticle
实例复制到另一个 vector ,并稍后重试更新它们。
我会在drawParticles()
中遵循类似的策略。这依赖于这样一个事实:绘制顺序对于粒子来说并不重要,这种情况经常发生。
关于c++ - 多个线程访问共享资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43697618/